📄 recordstore.java
字号:
try {
if (newData != null) {
newrh.write(newData, offset);
// NOTE: I/O exception leaves space allocated & unused
}
} catch (java.io.IOException ioe) {
throw new RecordStoreException("error moving record "
+ "data");
}
}
// update database header info and sync to file
dbVersion++;
storeDBState();
notifyRecordChangedListeners(recordId);
}
}
public RecordEnumeration enumerateRecords(RecordFilter filter,
RecordComparator comparator, boolean keepUpdated)
throws RecordStoreNotOpenException {
checkOpen();
return new RecordEnumerationImpl(this, filter, comparator, keepUpdated);
}
/*
* Private Memory Management Methods
*/
private RecordHeader findRecord(int recordId, boolean addToCache)
throws InvalidRecordIDException, java.io.IOException {
RecordHeader rh;
//int offset;
int cur_offset = dbFirstRecordOffset;
// if no records exist, throw an exception
if (cur_offset == 0) {
throw new InvalidRecordIDException();
}
// look for the record in the cache
rh = recHeadCache.get(recordId);
if (rh != null) {
return rh;
}
/*
* requested record header is NOT in cache... search through the linked
* list of records in the file.
*/
rh = new RecordHeader();
while (cur_offset != 0) {
rh.load(cur_offset);
if (rh.id == recordId) {
break;
} else {
cur_offset = rh.nextOffset;
}
}
if (cur_offset == 0) {
// hit the end of the linked list w/o finding record.
throw new InvalidRecordIDException();
}
if (addToCache) {
recHeadCache.insert(rh);
}
return rh;
}
private int getAllocSize(int numBytes) {
int rv;
int pad;
rv = DB_RECORD_HEADER_LENGTH + numBytes;
pad = DB_BLOCK_SIZE - (rv % DB_BLOCK_SIZE);
if (pad != DB_BLOCK_SIZE) {
rv += pad;
}
return rv;
}
private RecordHeader allocateNewRecordStorage(int id, int dataSize)
throws RecordStoreException, RecordStoreFullException {
int allocSize = getAllocSize(dataSize);
boolean foundBlock = false;
/*
* Traverse the free block linked list in the file, looking for the
* first fit
*/
RecordHeader block = new RecordHeader();
try {
int offset = dbFirstFreeBlockOffset;
while (offset != 0) {
block.load(offset);
// If block is big enough, use it.
if (block.blockSize >= allocSize) {
foundBlock = true;
break; // use this free block
}
offset = block.dataLenOrNextFree; // next free block
}
} catch (java.io.IOException ioe) {
throw new RecordStoreException("error finding first fit block");
}
if (foundBlock == false) {
/*
* No free block was found that would hold this record, so find the
* last (biggest offset) record in the file and append this record
* after it.
*/
// Is there room to grow the file?
if (RecordStoreFile.spaceAvailable() < allocSize) {
throw new RecordStoreFullException();
}
block = new RecordHeader(dbDataEnd, id, dbFirstRecordOffset,
allocSize, dataSize);
try {
block.store();
} catch (java.io.IOException ioe) {
throw new RecordStoreException("error writing "
+ "new record data");
}
dbFirstRecordOffset = dbDataEnd;
dbDataEnd += allocSize;
} else {
// block is where the new record should be stored
if (block.id != -1) {
throw new RecordStoreException("ALLOC ERR " + block.id
+ " is not a free block!");
}
removeFreeBlock(block); // remove from free block list
block.id = id;
if (block.blockSize - allocSize >= DB_BLOCK_SIZE
+ DB_RECORD_HEADER_LENGTH) {
splitRecord(block, allocSize); // sets block.blockSize
}
block.dataLenOrNextFree = dataSize;
try {
block.store();
} catch (java.io.IOException ioe) {
throw new RecordStoreException("error writing free block "
+ "after alloc");
}
}
// add new record to cache
recHeadCache.insert(block);
return block;
}
private void splitRecord(RecordHeader recHead, int allocSize)
throws RecordStoreException {
RecordHeader newfb;
int extraSpace = recHead.blockSize - allocSize;
int oldBlockSize = recHead.blockSize;
recHead.blockSize = allocSize;
// only split records inside the linked list
if (recHead.offset != dbFirstRecordOffset) {
int fboffset = recHead.offset + allocSize;
newfb = new RecordHeader(fboffset, -1, recHead.offset, extraSpace,
0);
try {
freeRecord(newfb); // write new free block to disk
RecordHeader prh = new RecordHeader(recHead.offset
+ oldBlockSize);
prh.nextOffset = fboffset;
prh.store();
recHeadCache.invalidate(prh.id);
storeDBState();
} catch (java.io.IOException ioe) {
throw new RecordStoreException("splitRecord error");
}
} else {
// drop free space at the end of the file
dbDataEnd = recHead.offset + recHead.blockSize;
}
}
private void freeRecord(RecordHeader rh) throws RecordStoreException {
if (rh.offset == dbFirstRecordOffset) {
// don't put free blocks at the end of the record file
dbFirstRecordOffset = rh.nextOffset;
dbDataEnd = rh.offset;
} else {
rh.id = -1; // indicate this is a free block
rh.dataLenOrNextFree = dbFirstFreeBlockOffset;
// insert this new free block at front of free list
dbFirstFreeBlockOffset = rh.offset;
try {
rh.store();
} catch (java.io.IOException ioe) {
throw new RecordStoreException("free record failed");
}
}
}
private void removeFreeBlock(RecordHeader blockToFree)
throws RecordStoreException {
RecordHeader block = new RecordHeader();
RecordHeader prev = new RecordHeader();
RecordHeader tmp = null;
try {
int offset = dbFirstFreeBlockOffset;
while (offset != 0) {
block.load(offset);
if (block.offset == blockToFree.offset) {
if (block.id != -1) {
throw new RecordStoreException("removeFreeBlock id"
+ " is not -1");
}
if (prev.offset == 0) {
// Set next free block as new freelist head
dbFirstFreeBlockOffset = block.dataLenOrNextFree;
} else {
/*
* Update previous block's pointer to the block this
* block was pointing to
*/
prev.dataLenOrNextFree = block.dataLenOrNextFree;
prev.store();
}
}
offset = block.dataLenOrNextFree;
// avoid creating lots of garbage!
tmp = prev;
prev = block;
block = tmp;
}
} catch (java.io.IOException ioe) {
throw new RecordStoreException("removeFreeBlock block not found");
}
}
private void storeDBState() throws RecordStoreException {
try {
// set modification time
dbLastModified = System.currentTimeMillis();
// Capture the db state into the byte array
RecordStore.putInt(dbNumLiveRecords, dbState, RS_NUM_LIVE);
RecordStore.putInt(dbAuthMode, dbState, RS_AUTHMODE);
RecordStore.putInt(dbVersion, dbState, RS_VERSION);
RecordStore.putInt(dbNextRecordID, dbState, RS_NEXT_ID);
RecordStore.putInt(dbFirstRecordOffset, dbState, RS_REC_START);
RecordStore.putInt(dbFirstFreeBlockOffset, dbState, RS_FREE_START);
RecordStore.putLong(dbLastModified, dbState, RS_LAST_MODIFIED);
RecordStore.putInt(dbDataStart, dbState, RS_DATA_START);
RecordStore.putInt(dbDataEnd, dbState, RS_DATA_END);
// Write the state to the db file
dbraf.seek(SIGNATURE_LENGTH); // skip RS header 8 bytes
int numbytes = DB_INIT.length - SIGNATURE_LENGTH;
dbraf.write(dbState, SIGNATURE_LENGTH, numbytes);
} catch (java.io.IOException ioe) {
throw new RecordStoreException("error writing record store "
+ "attributes");
}
}
/*
* Package Private Methods
*/
public boolean isOpen() {
if (dbraf == null) {
return false;
}
return true;
}
/*
* Private Utility Methods
*/
private void checkOpen() throws RecordStoreNotOpenException {
if (dbraf == null) {
throw new RecordStoreNotOpenException();
}
}
private void notifyRecordChangedListeners(int recordId) {
for (int i = 0; i < recordListener.size(); i++) {
RecordListener rl = (RecordListener) recordListener.elementAt(i);
rl.recordChanged(this, recordId);
}
}
private void notifyRecordAddedListeners(int recordId) {
for (int i = 0; i < recordListener.size(); i++) {
RecordListener rl = (RecordListener) recordListener.elementAt(i);
rl.recordAdded(this, recordId);
}
}
private void notifyRecordDeletedListeners(int recordId) {
for (int i = 0; i < recordListener.size(); i++) {
RecordListener rl = (RecordListener) recordListener.elementAt(i);
rl.recordDeleted(this, recordId);
}
}
static int getInt(byte[] data, int offset) {
int r = data[offset++];
r = (r << 8) | ((int) (data[offset++]) & 0xff);
r = (r << 8) | ((int) (data[offset++]) & 0xff);
r = (r << 8) | ((int) (data[offset++]) & 0xff);
return r;
}
static long getLong(byte[] data, int offset) {
long r = data[offset++];
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
r = (r << 8) | ((long) (data[offset++]) & 0xff);
return r;
}
static int putInt(int i, byte[] data, int offset) {
data[offset++] = (byte) ((i >> 24) & 0xff);
data[offset++] = (byte) ((i >> 16) & 0xff);
data[offset++] = (byte) ((i >> 8) & 0xff);
data[offset] = (byte) (i & 0xff);
return 4;
}
static int putLong(long l, byte[] data, int offset) {
data[offset++] = (byte) ((l >> 56) & 0xff);
data[offset++] = (byte) ((l >> 48) & 0xff);
data[offset++] = (byte) ((l >> 40) & 0xff);
data[offset++] = (byte) ((l >> 32) & 0xff);
data[offset++] = (byte) ((l >> 24) & 0xff);
data[offset++] = (byte) ((l >> 16) & 0xff);
data[offset++] = (byte) ((l >> 8) & 0xff);
data[offset] = (byte) (l & 0xff);
return 8;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -