diskfile.java
来自「非常棒的java数据库」· Java 代码 · 共 1,060 行 · 第 1/3 页
JAVA
1,060 行
int blockCount = s.readInt();
if (SysProperties.CHECK && blockCount < 0) {
throw Message.getInternalError();
}
if (blockCount == 0) {
setUnused(null, i, 1);
i++;
} else {
int id = s.readInt();
if (SysProperties.CHECK && id < 0) {
throw Message.getInternalError();
}
Storage storage = database.getStorage(id, this);
setUnused(null, i, blockCount);
setBlockOwner(null, storage, i, blockCount, true);
storage.incrementRecordCount();
i += blockCount;
}
}
database.setProgress(DatabaseEventListener.STATE_SCAN_FILE, this.fileName, fileBlockCount, fileBlockCount);
init = true;
}
}
public void flush() throws SQLException {
synchronized (database) {
database.checkPowerOff();
ObjectArray list = cache.getAllChanged();
CacheObject.sort(list);
for (int i = 0; i < list.size(); i++) {
Record rec = (Record) list.get(i);
writeBack(rec);
}
for (int i = 0; i < fileBlockCount; i++) {
i = deleted.nextSetBit(i);
if (i < 0) {
break;
}
if (deleted.get(i)) {
writeDirectDeleted(i, 1);
deleted.clear(i);
}
}
}
}
// this implementation accesses the file in a linear way
// public void flushNew() throws SQLException {
// int todoTest;
// synchronized (database) {
// database.checkPowerOff();
// ObjectArray list = cache.getAllChanged();
// CacheObject.sort(list);
// int deletePos = deleted.nextSetBit(0);
// int writeIndex = 0;
// Record writeRecord = null;
// while (true) {
// if (writeRecord == null && writeIndex < list.size()) {
// writeRecord = (Record) list.get(writeIndex++);
// }
// if (writeRecord != null &&
// (deletePos < 0 || writeRecord.getPos() < deletePos)) {
// writeBack(writeRecord);
// writeRecord = null;
// } else if (deletePos < fileBlockCount && deletePos >= 0) {
// writeDirectDeleted(deletePos, 1);
// deleted.clear(deletePos);
// deletePos = deleted.nextSetBit(deletePos);
// } else {
// break;
// }
// }
// }
// }
public void close() throws SQLException {
synchronized (database) {
SQLException closeException = null;
if (!database.getReadOnly()) {
try {
flush();
} catch (SQLException e) {
closeException = e;
}
}
cache.clear();
// continue with close even if flush was not possible (file storage
// problem)
if (file != null) {
file.closeSilently();
file = null;
}
if (closeException != null) {
throw closeException;
}
readCount = writeCount = 0;
}
}
private void go(int block) throws SQLException {
database.checkPowerOff();
file.seek(getFilePos(block));
}
private long getFilePos(int block) {
return ((long) block * BLOCK_SIZE) + OFFSET;
}
Record getRecordIfStored(Session session, int pos, RecordReader reader, int storageId)
throws SQLException {
synchronized (database) {
try {
int owner = getPageOwner(getPage(pos));
if (owner != storageId) {
return null;
}
go(pos);
rowBuff.reset();
byte[] buff = rowBuff.getBytes();
file.readFully(buff, 0, BLOCK_SIZE);
DataPage s = DataPage.create(database, buff);
s.readInt(); // blockCount
int id = s.readInt();
if (id != storageId) {
return null;
}
} catch (Exception e) {
return null;
}
return getRecord(session, pos, reader, storageId);
}
}
Record getRecord(Session session, int pos, RecordReader reader, int storageId) throws SQLException {
synchronized (database) {
if (file == null) {
throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
}
Record record = (Record) cache.get(pos);
if (record != null) {
return record;
}
readCount++;
go(pos);
rowBuff.reset();
byte[] buff = rowBuff.getBytes();
file.readFully(buff, 0, BLOCK_SIZE);
DataPage s = DataPage.create(database, buff);
int blockCount = s.readInt();
int id = s.readInt();
if (SysProperties.CHECK && storageId != id) {
throw Message.getInternalError("File ID mismatch got=" + id + " expected=" + storageId + " pos=" + pos
+ " " + logChanges + " " + this + " blockCount:" + blockCount);
}
if (SysProperties.CHECK && blockCount == 0) {
throw Message.getInternalError("0 blocks to read pos=" + pos);
}
if (blockCount > 1) {
byte[] b2 = new byte[blockCount * BLOCK_SIZE];
System.arraycopy(buff, 0, b2, 0, BLOCK_SIZE);
buff = b2;
file.readFully(buff, BLOCK_SIZE, blockCount * BLOCK_SIZE - BLOCK_SIZE);
s = DataPage.create(database, buff);
s.readInt();
s.readInt();
}
s.check(blockCount * BLOCK_SIZE);
Record r = reader.read(session, s);
r.setStorageId(storageId);
r.setPos(pos);
r.setBlockCount(blockCount);
cache.put(r);
return r;
}
}
int allocate(Storage storage, int blockCount) throws SQLException {
reuseSpace();
synchronized (database) {
if (file == null) {
throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
}
blockCount = getPage(blockCount + BLOCKS_PER_PAGE - 1) * BLOCKS_PER_PAGE;
int lastPage = getPage(getBlockCount());
int pageCount = getPage(blockCount);
int pos = -1;
boolean found = false;
for (int i = 0; i < lastPage; i++) {
found = true;
for (int j = i; j < i + pageCount; j++) {
if (j >= lastPage || getPageOwner(j) != FREE_PAGE) {
found = false;
break;
}
}
if (found) {
pos = i * BLOCKS_PER_PAGE;
break;
}
}
if (!found) {
int max = getBlockCount();
pos = MathUtils.roundUp(max, BLOCKS_PER_PAGE);
if (rowBuff instanceof DataPageText) {
if (pos > max) {
writeDirectDeleted(max, pos - max);
}
writeDirectDeleted(pos, blockCount);
} else {
long min = ((long) pos + blockCount) * BLOCK_SIZE;
min = MathUtils.scaleUp50Percent(Constants.FILE_MIN_SIZE, min, Constants.FILE_PAGE_SIZE, Constants.FILE_MAX_INCREMENT) + OFFSET;
if (min > file.length()) {
file.setLength(min);
database.notifyFileSize(min);
}
}
}
setBlockOwner(null, storage, pos, blockCount, false);
for (int i = 0; i < blockCount; i++) {
storage.free(i + pos, 1);
}
return pos;
}
}
private void setBlockOwner(Session session, Storage storage, int pos, int blockCount, boolean inUse) throws SQLException {
if (pos + blockCount > fileBlockCount) {
setBlockCount(pos + blockCount);
}
if (!inUse) {
setUnused(session, pos, blockCount);
}
for (int i = getPage(pos); i <= getPage(pos + blockCount - 1); i++) {
setPageOwner(i, storage.getId());
}
if (inUse) {
used.setRange(pos, blockCount, true);
deleted.setRange(pos, blockCount, false);
}
}
private void setUnused(Session session, int pos, int blockCount) throws SQLException {
if (pos + blockCount > fileBlockCount) {
setBlockCount(pos + blockCount);
}
uncommittedDelete(session);
for (int i = pos; i < pos + blockCount; i++) {
used.clear(i);
if ((i % BLOCKS_PER_PAGE == 0) && (pos + blockCount >= i + BLOCKS_PER_PAGE)) {
// if this is the first page of a block and if the whole page is free
freePage(getPage(i));
}
}
}
void reuseSpace() throws SQLException {
if (SysProperties.REUSE_SPACE_QUICKLY) {
if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) {
Session[] sessions = database.getSessions();
int oldest = 0;
for (int i = 0; i < sessions.length; i++) {
int deleteId = sessions[i].getLastUncommittedDelete();
if (oldest == 0 || (deleteId != 0 && deleteId < oldest)) {
oldest = deleteId;
}
}
for (Iterator it = potentiallyFreePages.iterator(); it.hasNext();) {
int p = ((Integer) it.next()).intValue();
if (oldest == 0) {
setPageOwner(p, FREE_PAGE);
it.remove();
}
}
}
}
}
void uncommittedDelete(Session session) throws SQLException {
if (session != null && logChanges && SysProperties.REUSE_SPACE_QUICKLY) {
int deleteId = session.getLastUncommittedDelete();
if (deleteId == 0 || deleteId < nextDeleteId) {
deleteId = ++nextDeleteId;
session.setLastUncommittedDelete(deleteId);
}
}
}
void freePage(int page) throws SQLException {
if (!logChanges) {
setPageOwner(page, FREE_PAGE);
} else {
if (SysProperties.REUSE_SPACE_QUICKLY) {
potentiallyFreePages.add(ObjectUtils.getInteger(page));
reuseSpace();
}
}
}
int getPage(int pos) {
return pos >>> BLOCK_PAGE_PAGE_SHIFT;
}
int getPageOwner(int page) {
if (page * BLOCKS_PER_PAGE > fileBlockCount || page >= pageOwners.size()) {
return FREE_PAGE;
}
return pageOwners.get(page);
}
public void setPageOwner(int page, int storageId) throws SQLException {
int old = pageOwners.get(page);
if (old == storageId) {
return;
}
if (SysProperties.CHECK && old >= 0 && storageId >= 0 && old != storageId) {
for (int i = 0; i < BLOCKS_PER_PAGE; i++) {
if (used.get(i + page * BLOCKS_PER_PAGE)) {
throw Message.getInternalError(
"double allocation in file " + fileName +
" page " + page +
" blocks " + (BLOCKS_PER_PAGE * page) +
"-" + (BLOCKS_PER_PAGE * (page + 1) - 1));
}
}
}
if (old >= 0) {
database.getStorage(old, this).removePage(page);
if (!logChanges) {
// need to clean the page, otherwise it may never get cleaned
// and can become corrupted
writeDirectDeleted(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE);
}
}
if (storageId >= 0) {
database.getStorage(storageId, this).addPage(page);
if (SysProperties.REUSE_SPACE_QUICKLY) {
potentiallyFreePages.remove(ObjectUtils.getInteger(page));
}
}
pageOwners.set(page, storageId);
}
void setUsed(int pos, int blockCount) {
synchronized (database) {
if (pos + blockCount > fileBlockCount) {
setBlockCount(pos + blockCount);
}
used.setRange(pos, blockCount, true);
deleted.setRange(pos, blockCount, false);
}
}
public void delete() throws SQLException {
synchronized (database) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?