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 + -
显示快捷键?