⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 recordstore.java

📁 有关j2me的很好的例子可以研究一下
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
    }    /**     * Returns all of the recordId's currently in the record store.     *     * MUST be called after obtaining rsLock, e.g in a      * <code>synchronized (rsLock) {</code> block.     *     * @return an array of the recordId's currently in the record store     *         or null if the record store is closed.     */    int[] getRecordIDs()     {	if (dbraf == null) // lower overhead than checkOpen() 	    return null;	int index = 0;	int[] tmp = new int[dbNumLiveRecords];	int offset = dbFirstRecordOffset; // start at beginning of file	RecordHeader rh = new RecordHeader(); 	try {	    while (offset != 0) {		rh.load(offset);		if (rh.id > 0) {		    tmp[index++] = rh.id;		}		offset = rh.nextOffset;	    }	} catch (java.io.IOException ioe) {	    return null;	}	return tmp;    }    /**     * Remove free blocks from the record store and compact records     * with data into as small a space in <code>rsFile</code> as     * possible.  Operates from smallest to greatest offset in      * <code>rsFile</code>, copying data in chunks towards the      * beginning of the file, and updating record store meta-data     * as it progresses.     *     * Warning: This is a slow operation that scales linearly     * with rsFile size.       *     * @exception RecordStoreNotOpenException if this record store      *            is closed     * @exception RecordStoreException if an error occurs during record      *            store compaction     */    private void compactRecords() throws RecordStoreNotOpenException, 	RecordStoreException {	int offset = dbDataStart;  // after record store header structure	int target = 0;	int bytesLeft;	int numToMove;	byte[] chunkBuffer = new byte[DB_COMPACTBUFFER_SIZE];		RecordHeader rh = new RecordHeader();		int prevRec = 0;	while (offset < dbDataEnd) {	    try {		rh.load(offset);	    } catch (java.io.IOException ioe) {		// NOTE - should throw some exception here		System.out.println("Unexpected IOException in CompactRS!");	    }	    	    if (rh.id == -1) {          // a free block		if (target == 0) {		    target = offset; 		} // else skip free block		offset += rh.blockSize;	    } else {                    // a record block		if (target == 0) {		    // No move needed so far.		    prevRec = offset;		    offset += rh.blockSize;		} else {		    int old_offset = target;		    // Move a record back in the file		    rh.offset = target;		    rh.nextOffset = prevRec;		    try {			rh.store();			offset += DB_RECORD_HEADER_LENGTH;			target += DB_RECORD_HEADER_LENGTH;			bytesLeft = (rh.blockSize - DB_RECORD_HEADER_LENGTH);			while (bytesLeft > 0) {			    if (bytesLeft < DB_COMPACTBUFFER_SIZE) {				numToMove = bytesLeft;			    } else {				numToMove = DB_COMPACTBUFFER_SIZE;			    }			    dbraf.seek(offset);			    dbraf.read(chunkBuffer, 0, numToMove);			    dbraf.seek(target);			    dbraf.write(chunkBuffer, 0, numToMove);			    offset += numToMove;			    target += numToMove;			    bytesLeft -= numToMove;			} 		    } catch (java.io.IOException ioe) {			// NOTE - should throw some exception here			System.out.println("Unexpected IOException " +					   "in CompactRS!");		    }		    prevRec = old_offset;		}	    }	}	if (rh.offset != 0)	    dbDataEnd = rh.offset + rh.blockSize;	dbFirstRecordOffset = rh.offset;	dbFirstFreeBlockOffset = 0;	storeDBState();    }    /*     * Internal Classes       */    /**     * A class representing a RecordHeader, which may be the start of a      * record block or a free block.  (In a free block, only the      * <code> NextOffset </code> and <code> BlockSize </code> fields     * are valid.)  Currently it is a conveinience structure, with     * fields visible and directly modifyable by the enclosing     * RecordStore class.     */    private class RecordHeader {	/*	 * Each record is laid out in the file system as follows:	 * Bytes - Usage	 * 00-03 - Record ID	 * 04-07 - Next record offset	 * 08-11 - Record size...total (in bytes, big endian).	 * 12-15 - Length of Data.  This is stored separately for the case 	 *         where a record has gotten smaller.	 * 16-xx - Data	 *	 * Each free block is laid out in the file system as follows:	 * Bytes - Usage	 * 00-03 - Free block ID (set to -1)	 * 04-07 - Next record offset (not used by free block)	 * 08-11 - Free block size in bytes (in bytes, big endian)	 * 12-15 - Next free block offset (zero if this is the last free block)	 * 16-xx - Data (not used by free block)	 */	/** REC_ID offset */	private static final int REC_ID = 0;	/** NEXT_OFFSET offset */	private static final int NEXT_OFFSET = 4;	/** BLOCK_SIZE offset */	private static final int BLOCK_SIZE = 8;	/** 	 * data length offset of record block or next free block 	 * offset of free block 	 */	private static final int DATALEN_OR_NEXTFREE = 12;	/** DATA_OFFSET offset (offset to record data) */	private static final int DATA_OFFSET = 16; 		/** offset of the record block or free block in RSFile */	int offset;	/** record id -or- -1 if free block */	int id;	/** next record offset */	int nextOffset;	/** record size -or- free block size */	int blockSize;  	/** record length -or- next free block offset */	int dataLenOrNextFree;		/**	 * default RecordHeader constructor - creates an empty header	 */	RecordHeader() { }		/**	 * Creates a new RecordHeader and initializes it with data	 * read from a RecordStoreFile at offset <code> offset </code>.	 *	 * @param _offset seek offset in RecordStoreFile of desired 	 *        RecordHeader.	 *	 * @exception IOException if there is an error reading the	 *            underlying RecordStoreFile.	 */	RecordHeader(int _offset) throws java.io.IOException {	    load(_offset);	}	/**	 * Creates a new RecordHeader and initializes it with data 	 * provided in the parameters.  This RecordHeader will not	 * be stored (on disk/in persistant storage) until the 	 * <code> store </code> method is called.	 *	 * @param _offset offset in RecordStoreFile where this 	 *        RecordHeader should be stored.	 * @param _id record id of this new RecordHeader	 *	 * @param next_offset next RecordHeader in linked list of	 *        records.	 * @param size total size of the storage block allocated for	 *        this record or free block.	 * @param len_or_free length of data in this record (may be shorter	 *        than <code>size</code> -or- next free block if this	 *        header is a free block header	 */	RecordHeader(int _offset, int _id, int next_offset, 		     int size, int len_or_free) {	    offset = _offset;	    id = _id;	    nextOffset = next_offset;	    blockSize = size;	    dataLenOrNextFree = len_or_free;	}	/**	 * Re-uses a RecordHeader and initializes it with data	 * read from a RecordStoreFile at offset <code> offset </code>.	 *	 * @param _offset seek offset in RecordStoreFile of desired 	 *        RecordHeader.	 *	 * @exception IOException if there is an error reading the	 *            underlying RecordStoreFile	 */		void load(int _offset) throws java.io.IOException {	    offset = _offset;	    	    // read rec header from file.	    dbraf.seek(offset);	    dbraf.read(recHeadBuf, 0, DB_RECORD_HEADER_LENGTH);	    	    id = RecordStore.getInt(recHeadBuf, REC_ID);	    nextOffset = RecordStore.getInt(recHeadBuf, NEXT_OFFSET);	    blockSize = RecordStore.getInt(recHeadBuf, BLOCK_SIZE);	    dataLenOrNextFree = RecordStore.getInt(recHeadBuf, 					       DATALEN_OR_NEXTFREE);	}		/**	 * Flushes an in memory RecordHeader instance to storage in a 	 * a RecordStoreFile at <code>offset</code>.	 * @exception IOException if there is an error writing the	 *            underlying RecordStoreFile	 */		void store() throws java.io.IOException {	    RecordStore.putInt(id, recHeadBuf, REC_ID);	    RecordStore.putInt(nextOffset, recHeadBuf, NEXT_OFFSET);	    RecordStore.putInt(blockSize, recHeadBuf, BLOCK_SIZE);	    RecordStore.putInt(dataLenOrNextFree, recHeadBuf, 			       DATALEN_OR_NEXTFREE);	    	    // write record header;	    dbraf.seek(offset);	    dbraf.write(recHeadBuf, 0, DB_RECORD_HEADER_LENGTH);	}	/**	 * Reads data associated with this record from storage (a	 * RecordStoreFile) at <code>offset</code>.	 *	 * Assumes CALLER has ensured <code>dataLenOrNextFree</code> is set 	 * correctly, and that <code>dataLenOrNextFree</code> bytes will 	 * fit into the array.	 *	 * @param buf data is read into this buffer.	 * @param _offset position in <code>buf</code> to start reading	 *        data into.	 *	 * @return number of bytes read.	 *	 * @exception IOException if there is an error reading the	 *            underlying RecordStoreFile	 */		int read(byte[] buf, int _offset) throws java.io.IOException {	    dbraf.seek(offset + DATA_OFFSET);	    return dbraf.read(buf, _offset, dataLenOrNextFree);	}	/**	 * Writes data associated with this record to storage (a 	 * RecordStoreFile) at <code>offset</code>.	 *	 * Assumes CALLER has ensured <code>dataLenOrNextFree</code> is	 * set correctly.	 *	 * @param buf data to store in this record.	 * @param _offset point in <code>buf</code> to begin write from.	 *	 * @exception IOException if there is an error writing the	 *            underlying RecordStoreFile.	 */		void write(byte[] buf, int _offset) throws java.io.IOException {	    dbraf.seek(offset + DATA_OFFSET);	    dbraf.write(buf, _offset, dataLenOrNextFree);	}    }    /**     * RecordHeaderCache providing a per RecordStore, in memory cache of      * recent  RecordHeader lookups in order to absorb in many cases the     * need to search for records on disk.  Since the on disk data model     * for record storage is a linked list, this can improve performance     * when a record is accessed frequently.       *     * (Currently implemented in a simple, direct mapped way.  Could be     * modified to be random replacement/linear lookup, etc.  These design     * considerations should be determined by measuring cache performance     * on representative RMS use cases.)     */    private class RecordHeaderCache {	/** a cache of RecordHeader objects */	private RecordHeader[] mCache;		/**	 * Returns a new RecordHeaderCache able to hold up to <code>	 * size</code> record headers.	 *	 * @param size max number of RecordHeader objects allowed 	 *        in <code>mCache</code>.	 */	RecordHeaderCache(int size) {	    mCache = new RecordHeader[size];	}		/**	 * Returns a RecordHeader for record <code>rec_id</code> or 	 * null if the desired record header is not in the cache	 *	 * @param rec_id record id of the desired record header.	 *	 * @return a RecordHeader object for record 	 *         <code>rec_id</code>.	 */	RecordHeader get(int rec_id) {	    int idx = rec_id % mCache.length;	    RecordHeader rh = (RecordHeader)mCache[idx];	    if ((mCache[idx] != null) && (mCache[idx].id != rec_id))		return null;	    return rh;	}		/**	 * Inserts a new RecordHeader into the cache.	 *	 * @param rh a RecordHeader to add to the cache.	 */	void insert(RecordHeader rh) {	    int idx = rh.id % mCache.length;	    mCache[idx] = rh;	}		/**	 * Removes a RecordHeader from the cache if it exists,	 * otherwise does nothing.  Used in the case that the	 * cached RecordHeader is no longer valid.	 *	 * @param rec_id the record ID of the RecordHeader to 	 *        invalidate	 */	void invalidate(int rec_id) {	    if (rec_id > 0) {		int idx = rec_id % mCache.length;		if ((mCache[idx] != null) && 		    (mCache[idx].id == rec_id)) {		mCache[idx] = null;		}	    }	}    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -