recordstoreindex.java
来自「This is a resource based on j2me embedde」· Java 代码 · 共 1,179 行 · 第 1/3 页
JAVA
1,179 行
/* * * * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */package com.sun.midp.rms;import java.io.IOException;import javax.microedition.rms.*;import com.sun.midp.log.Logging;import com.sun.midp.log.LogChannels;/** * A class implementing a index of the record store. * * Methods used by the RecordStoreImpl * close() * deleteIndex() * getRecordIDs() * getRecordHeader() * getFreeBlock() * updateBlock() * deleteRecordIndex() * removeBlock() * */class RecordStoreIndex { /* * The layout of the database file is as follows: * * Bytes - Usage * 00-03 - Size of index file (big endian) * 04-07 - Offset to recordId tree root (big endian) * 08-11 - Offset to free block tree root (big endian) * 12-15 - Offset to the list of free tree blocks (big endian) * 16-xx - Tree Blocks */ /** IDX_SIZE offset */ static final int IDX0_SIZE = 0; /** IDX_ID_ROOT offset */ static final int IDX1_ID_ROOT = 4; /** IDX_FREE_ROOT offset */ static final int IDX2_FREE_BLOCK_ROOT = 8; /** IDX_FREE_NODES offset */ static final int IDX3_FREE_NODE_HEAD = 12; /** Size of the index header */ static final int IDX_HEADER_SIZE = 16; /** The maximum number of data elements in each node */ static final int NODE_ELEMENTS = 8; /** The size of the tree blocks */ static final int NODE_SIZE = 4 + (NODE_ELEMENTS * (4 + 4 + 4)); /** The Record Store that this object indexes */ private AbstractRecordStoreImpl recordStore; /** The Record Store database file */ private AbstractRecordStoreFile dbFile; /** The Record Store database index file */ private AbstractRecordStoreFile idxFile; /** The header of the index file */ private byte[] idxHeader = new byte[IDX_HEADER_SIZE]; /** The node buffer for initializing nodes */ private byte[] nodeBuf = new byte[NODE_SIZE]; /** * Constructor for creating an index object for the given Record Store. * * @param rs record store that this object indexes * @param suiteId unique ID of the suite that owns the store * @param recordStoreName a string to name the record store * * @exception IOException if there are any file errors */ RecordStoreIndex(AbstractRecordStoreImpl rs, int suiteId, String recordStoreName) throws IOException { recordStore = rs; if (rs != null) { dbFile = rs.getDbFile(); } boolean exist = RecordStoreUtil.exists(suiteId, recordStoreName, AbstractRecordStoreFile.IDX_EXTENSION); idxFile = rs.createIndexFile(suiteId, recordStoreName); if (exist) { // load header if (idxFile.read(idxHeader) != IDX_HEADER_SIZE) { throw new IOException("Index file corrupted"); } } else { RecordStoreUtil.putInt(IDX_HEADER_SIZE + NODE_SIZE * 2, idxHeader, IDX0_SIZE); RecordStoreUtil.putInt(IDX_HEADER_SIZE, idxHeader, IDX1_ID_ROOT); RecordStoreUtil.putInt(IDX_HEADER_SIZE + NODE_SIZE, idxHeader, IDX2_FREE_BLOCK_ROOT); idxFile.write(idxHeader); idxFile.write(nodeBuf); idxFile.write(nodeBuf); idxFile.commitWrite(); } } /** * Closes the index file. * * @exception IOException if there are any file errors */ void close() throws IOException { idxFile.close(); } /** * Deletes index files of the named record store. MIDlet suites are * only allowed to delete their own record stores. * * @param suiteId ID of the MIDlet suite that owns the record store * @param recordStoreName the MIDlet suite unique record store to * delete * @return <code>true</code> if file was found and deleted successfully, * <code>false</code> otherwise. */ static boolean deleteIndex(int suiteId, String recordStoreName) { return RecordStoreUtil.quietDeleteFile(suiteId, recordStoreName, AbstractRecordStoreFile.IDX_EXTENSION); } /** * Returns all of the recordId's currently in the record store index. * * @return an array of the recordId's currently in the index. */ int[] getRecordIDs() { int count = recordStore.getNumRecords(); int[] recordIdList = new int[count]; getRecordIds(recordIdList); return recordIdList; } /** * Returns places all of the recordId's in the index. * If the array is not big enough, the recordId list will be * limited to the size of the given array. * * @param recordIdList array to place the recordId's * * @return the number of recordId's placed in the array. */ int getRecordIds(int[] recordIdList) { int count = 0; try { Node node = new Node(idxFile); node.load(getRecordIdRootOffset()); count = walk(node, recordIdList, 0); } catch (IOException e) { if (Logging.REPORT_LEVEL <= Logging.ERROR) { Logging.report(Logging.ERROR, LogChannels.LC_RMS, "Could not walk the tree"); } } return count; } /** * Finds the record header for the given record and returns the * offset to the header. * * @param recordId the ID of the record to use in this operation * @param header the header of the block to free * * @exception IOException if there is an error accessing the db file * @exception InvalidRecordIDException if the recordId is invalid * * @return the offset in the db file of the block added */ int getRecordHeader(int recordId, byte[] header) throws IOException, InvalidRecordIDException { if (recordId <= 0) { throw new InvalidRecordIDException("error finding record data"); } int loc_offset = getBlockOffsetOfRecord(recordId); if (loc_offset == 0) { // did not find the recordId throw new InvalidRecordIDException(); } // read the header dbFile.seek(loc_offset); // read the block header if (dbFile.read(header) != AbstractRecordStoreImpl.BLOCK_HEADER_SIZE) { // did not find the recordId throw new InvalidRecordIDException(); } return loc_offset; } /** * Returns the offset to the header for the given recordId * * @param recordId the ID of the record to use in this operation * * @exception IOException if there is an error accessing the db file * @exception InvalidRecordIDException if the recordId is invalid * * @return the offset in the db file of the record block */ int getBlockOffsetOfRecord(int recordId) throws IOException, InvalidRecordIDException { Node node = new Node(idxFile); node.load(getRecordIdRootOffset()); int loc_offset = getKeyValue(node, recordId); if (loc_offset == 0) { // did not find the recordId throw new InvalidRecordIDException(); } return loc_offset; } /** * Updates the index of the given block and its offset. * * @param blockOffset the offset in db file to the block to update * @param header the header of the block to update * * @exception IOException if there is an error accessing the index file */ void updateBlock(int blockOffset, byte[] header) throws IOException { int recordId = RecordStoreUtil.getInt(header, 0); if (recordId > 0) { updateRecordId(recordId, blockOffset); } } /** * Updates the given recordId with the given offset. Adds the * recordId if it did not already exist. * * @param recordId the id of the record * @param blockOffset the offset in db file to the block to update * * @exception IOException if there is an error accessing the index file */ void updateRecordId(int recordId, int blockOffset) throws IOException { Node node = new Node(idxFile); node.load(getRecordIdRootOffset()); // update the key int newOffset = updateKey(node, recordId, blockOffset); // check if a new root node was added if (newOffset > 0) { // save the new root node offset setRecordIdRootOffset(newOffset); } } /** * The record is deleted from the record store index. * * @param recordId the ID of the record index to delete * * @exception IOException if there is an error accessing the db index */ void deleteRecordIndex(int recordId) throws IOException { int rootOffset = getRecordIdRootOffset(); Node node = new Node(idxFile); node.load(rootOffset); // find the key's node int loc_offset = deleteKey(node, recordId); // check if the offset of a new root was returned if (loc_offset > 0) { // new root, free old one freeNode(rootOffset); // save the new root setRecordIdRootOffset(loc_offset); } } /** * Searches for a free block large enough for the record. * * @param header a block header with the size set to the record data size * * @exception IOException if there is an error accessing the db file * * @return the offset in the db file of the block added */ int getFreeBlock(byte[] header) throws IOException { int targetSize = RecordStoreUtil. calculateBlockSize(RecordStoreUtil.getInt(header, 4)); int currentId = 0; int currentOffset = AbstractRecordStoreImpl.DB_HEADER_SIZE; int currentSize = 0; // search through the data blocks for a free block that is large enough while (currentOffset < recordStore.getSize()) { // seek to the next offset dbFile.seek(currentOffset); // read the block header if (dbFile.read(header) != AbstractRecordStoreImpl.BLOCK_HEADER_SIZE) { // did not find the recordId throw new IOException(); } currentId = RecordStoreUtil.getInt(header, 0); currentSize = RecordStoreUtil. calculateBlockSize(RecordStoreUtil.getInt(header, 4)); // check for a free block big enough to hold the data if (currentId < 0 && currentSize >= targetSize) { // a free block return currentOffset; } // added the block size to the currentOffset currentOffset += currentSize; } return 0; } /** * Removes the given block from the list of free blocks. * * @param blockOffset the offset in db file to the block to remove * @param header the header of the block to remove * * @exception IOException if there is an error accessing the db file */ void removeBlock(int blockOffset, byte[] header) throws IOException { } /** * Getter/Setter for header info */ /**
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?