📄 recordstore.java
字号:
public 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;
}
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();
}
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);
}
}
private class RecordHeaderCache {
/** a cache of RecordHeader objects */
private RecordHeader[] mCache;
RecordHeaderCache(int size) {
mCache = new RecordHeader[size];
}
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;
}
void insert(RecordHeader rh) {
int idx = rh.id % mCache.length;
mCache[idx] = rh;
}
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;
}
}
}
}
private boolean checkOwner() {
// varies with currently running midlet suite
String myUid = RecordStoreFile.getUniqueIdPath(recordStoreName);
// fixed at the time dbraf is created
String rsfUid = dbraf.getUniqueIdPath();
if (myUid.equals(rsfUid)) {
return true;
} else {
return false;
}
}
private boolean checkWritable() {
if (checkOwner()) {
return true;
} else {
if (dbAuthMode == AUTHMODE_ANY) { // Read-Write mode
return true;
}
}
return false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -