Search in sources :

Example 36 with Page

use of org.h2.store.Page in project h2database by h2database.

the class Database method open.

private synchronized void open(int traceLevelFile, int traceLevelSystemOut) {
    if (persistent) {
        String dataFileName = databaseName + Constants.SUFFIX_OLD_DATABASE_FILE;
        boolean existsData = FileUtils.exists(dataFileName);
        String pageFileName = databaseName + Constants.SUFFIX_PAGE_FILE;
        String mvFileName = databaseName + Constants.SUFFIX_MV_FILE;
        boolean existsPage = FileUtils.exists(pageFileName);
        boolean existsMv = FileUtils.exists(mvFileName);
        if (existsData && (!existsPage && !existsMv)) {
            throw DbException.get(ErrorCode.FILE_VERSION_ERROR_1, "Old database: " + dataFileName + " - please convert the database " + "to a SQL script and re-create it.");
        }
        if (existsPage && !FileUtils.canWrite(pageFileName)) {
            readOnly = true;
        }
        if (existsMv && !FileUtils.canWrite(mvFileName)) {
            readOnly = true;
        }
        if (existsPage && !existsMv) {
            dbSettings.mvStore = false;
        }
        if (readOnly) {
            if (traceLevelFile >= TraceSystem.DEBUG) {
                String traceFile = Utils.getProperty("java.io.tmpdir", ".") + "/" + "h2_" + System.currentTimeMillis();
                traceSystem = new TraceSystem(traceFile + Constants.SUFFIX_TRACE_FILE);
            } else {
                traceSystem = new TraceSystem(null);
            }
        } else {
            traceSystem = new TraceSystem(databaseName + Constants.SUFFIX_TRACE_FILE);
        }
        traceSystem.setLevelFile(traceLevelFile);
        traceSystem.setLevelSystemOut(traceLevelSystemOut);
        trace = traceSystem.getTrace(Trace.DATABASE);
        trace.info("opening {0} (build {1})", databaseName, Constants.BUILD_ID);
        if (autoServerMode) {
            if (readOnly || fileLockMethod == FileLockMethod.NO || fileLockMethod == FileLockMethod.SERIALIZED || fileLockMethod == FileLockMethod.FS || !persistent) {
                throw DbException.getUnsupportedException("autoServerMode && (readOnly || " + "fileLockMethod == NO || " + "fileLockMethod == SERIALIZED || " + "fileLockMethod == FS || " + "inMemory)");
            }
        }
        String lockFileName = databaseName + Constants.SUFFIX_LOCK_FILE;
        if (readOnly) {
            if (FileUtils.exists(lockFileName)) {
                throw DbException.get(ErrorCode.DATABASE_ALREADY_OPEN_1, "Lock file exists: " + lockFileName);
            }
        }
        if (!readOnly && fileLockMethod != FileLockMethod.NO) {
            if (fileLockMethod != FileLockMethod.FS) {
                lock = new FileLock(traceSystem, lockFileName, Constants.LOCK_SLEEP);
                lock.lock(fileLockMethod);
                if (autoServerMode) {
                    startServer(lock.getUniqueId());
                }
            }
        }
        if (SysProperties.MODIFY_ON_WRITE) {
            while (isReconnectNeeded()) {
            // wait until others stopped writing
            }
        } else {
            while (isReconnectNeeded() && !beforeWriting()) {
            // wait until others stopped writing and
            // until we can write (the file is not yet open -
            // no need to re-connect)
            }
        }
        deleteOldTempFiles();
        starting = true;
        if (SysProperties.MODIFY_ON_WRITE) {
            try {
                getPageStore();
            } catch (DbException e) {
                if (e.getErrorCode() != ErrorCode.DATABASE_IS_READ_ONLY) {
                    throw e;
                }
                pageStore = null;
                while (!beforeWriting()) {
                // wait until others stopped writing and
                // until we can write (the file is not yet open -
                // no need to re-connect)
                }
                getPageStore();
            }
        } else {
            getPageStore();
        }
        starting = false;
        if (mvStore == null) {
            writer = WriterThread.create(this, writeDelay);
        } else {
            setWriteDelay(writeDelay);
        }
    } else {
        if (autoServerMode) {
            throw DbException.getUnsupportedException("autoServerMode && inMemory");
        }
        traceSystem = new TraceSystem(null);
        trace = traceSystem.getTrace(Trace.DATABASE);
        if (dbSettings.mvStore) {
            getPageStore();
        }
    }
    systemUser = new User(this, 0, SYSTEM_USER_NAME, true);
    mainSchema = new Schema(this, 0, Constants.SCHEMA_MAIN, systemUser, true);
    infoSchema = new Schema(this, -1, "INFORMATION_SCHEMA", systemUser, true);
    schemas.put(mainSchema.getName(), mainSchema);
    schemas.put(infoSchema.getName(), infoSchema);
    publicRole = new Role(this, 0, Constants.PUBLIC_ROLE_NAME, true);
    roles.put(Constants.PUBLIC_ROLE_NAME, publicRole);
    systemUser.setAdmin(true);
    systemSession = new Session(this, systemUser, ++nextSessionId);
    lobSession = new Session(this, systemUser, ++nextSessionId);
    CreateTableData data = new CreateTableData();
    ArrayList<Column> cols = data.columns;
    Column columnId = new Column("ID", Value.INT);
    columnId.setNullable(false);
    cols.add(columnId);
    cols.add(new Column("HEAD", Value.INT));
    cols.add(new Column("TYPE", Value.INT));
    cols.add(new Column("SQL", Value.STRING));
    boolean create = true;
    if (pageStore != null) {
        create = pageStore.isNew();
    }
    data.tableName = "SYS";
    data.id = 0;
    data.temporary = false;
    data.persistData = persistent;
    data.persistIndexes = persistent;
    data.create = create;
    data.isHidden = true;
    data.session = systemSession;
    meta = mainSchema.createTable(data);
    IndexColumn[] pkCols = IndexColumn.wrap(new Column[] { columnId });
    metaIdIndex = meta.addIndex(systemSession, "SYS_ID", 0, pkCols, IndexType.createPrimaryKey(false, false), true, null);
    objectIds.set(0);
    starting = true;
    Cursor cursor = metaIdIndex.find(systemSession, null, null);
    ArrayList<MetaRecord> records = New.arrayList();
    while (cursor.next()) {
        MetaRecord rec = new MetaRecord(cursor.get());
        objectIds.set(rec.getId());
        records.add(rec);
    }
    Collections.sort(records);
    synchronized (systemSession) {
        for (MetaRecord rec : records) {
            rec.execute(this, systemSession, eventListener);
        }
    }
    if (mvStore != null) {
        mvStore.initTransactions();
        mvStore.removeTemporaryMaps(objectIds);
    }
    recompileInvalidViews(systemSession);
    starting = false;
    if (!readOnly) {
        // set CREATE_BUILD in a new database
        String name = SetTypes.getTypeName(SetTypes.CREATE_BUILD);
        if (settings.get(name) == null) {
            Setting setting = new Setting(this, allocateObjectId(), name);
            setting.setIntValue(Constants.BUILD_ID);
            lockMeta(systemSession);
            addDatabaseObject(systemSession, setting);
        }
        // mark all ids used in the page store
        if (pageStore != null) {
            BitSet f = pageStore.getObjectIds();
            for (int i = 0, len = f.length(); i < len; i++) {
                if (f.get(i) && !objectIds.get(i)) {
                    trace.info("unused object id: " + i);
                    objectIds.set(i);
                }
            }
        }
    }
    getLobStorage().init();
    systemSession.commit(true);
    trace.info("opened {0}", databaseName);
    if (checkpointAllowed > 0) {
        afterWriting();
    }
}
Also used : Schema(org.h2.schema.Schema) BitSet(java.util.BitSet) TraceSystem(org.h2.message.TraceSystem) CreateTableData(org.h2.command.ddl.CreateTableData) Cursor(org.h2.index.Cursor) Constraint(org.h2.constraint.Constraint) DbException(org.h2.message.DbException) IndexColumn(org.h2.table.IndexColumn) IndexColumn(org.h2.table.IndexColumn) Column(org.h2.table.Column) FileLock(org.h2.store.FileLock)

Example 37 with Page

use of org.h2.store.Page in project h2database by h2database.

the class WebApp method query.

private String query() {
    String sql = attributes.getProperty("sql").trim();
    try {
        ScriptReader r = new ScriptReader(new StringReader(sql));
        final ArrayList<String> list = New.arrayList();
        while (true) {
            String s = r.readStatement();
            if (s == null) {
                break;
            }
            list.add(s);
        }
        final Connection conn = session.getConnection();
        if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
            String page = new String(server.getFile("result.jsp"), StandardCharsets.UTF_8);
            int idx = page.indexOf("${result}");
            // the first element of the list is the header, the last the
            // footer
            list.add(0, page.substring(0, idx));
            list.add(page.substring(idx + "${result}".length()));
            session.put("chunks", new Iterator<String>() {

                private int i;

                @Override
                public boolean hasNext() {
                    return i < list.size();
                }

                @Override
                public String next() {
                    String s = list.get(i++);
                    if (i == 1 || i == list.size()) {
                        return s;
                    }
                    StringBuilder b = new StringBuilder();
                    query(conn, s, i - 1, list.size() - 2, b);
                    return b.toString();
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            });
            return "result.jsp";
        }
        String result;
        StringBuilder buff = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            query(conn, s, i, list.size(), buff);
        }
        result = buff.toString();
        session.put("result", result);
    } catch (Throwable e) {
        session.put("result", getStackTrace(0, e, session.getContents().isH2()));
    }
    return "result.jsp";
}
Also used : StringReader(java.io.StringReader) Connection(java.sql.Connection) ScriptReader(org.h2.util.ScriptReader)

Example 38 with Page

use of org.h2.store.Page in project h2database by h2database.

the class Recover method dumpPageLogStream.

private void dumpPageLogStream(PrintWriter writer, int logKey, int logFirstTrunkPage, int logFirstDataPage, long pageCount) throws IOException {
    Data s = Data.create(this, pageSize);
    DataReader in = new DataReader(new PageInputStream(writer, this, store, logKey, logFirstTrunkPage, logFirstDataPage, pageSize));
    writer.println("---- Transaction log ----");
    CompressLZF compress = new CompressLZF();
    while (true) {
        int x = in.readByte();
        if (x < 0) {
            break;
        }
        if (x == PageLog.NOOP) {
        // ignore
        } else if (x == PageLog.UNDO) {
            int pageId = in.readVarInt();
            int size = in.readVarInt();
            byte[] data = new byte[pageSize];
            if (size == 0) {
                in.readFully(data, pageSize);
            } else if (size == 1) {
            // empty
            } else {
                byte[] compressBuffer = new byte[size];
                in.readFully(compressBuffer, size);
                try {
                    compress.expand(compressBuffer, 0, size, data, 0, pageSize);
                } catch (ArrayIndexOutOfBoundsException e) {
                    throw DbException.convertToIOException(e);
                }
            }
            String typeName = "";
            int type = data[0];
            boolean last = (type & Page.FLAG_LAST) != 0;
            type &= ~Page.FLAG_LAST;
            switch(type) {
                case Page.TYPE_EMPTY:
                    typeName = "empty";
                    break;
                case Page.TYPE_DATA_LEAF:
                    typeName = "data leaf " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_DATA_NODE:
                    typeName = "data node " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_DATA_OVERFLOW:
                    typeName = "data overflow " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_BTREE_LEAF:
                    typeName = "b-tree leaf " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_BTREE_NODE:
                    typeName = "b-tree node " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_FREE_LIST:
                    typeName = "free list " + (last ? "(last)" : "");
                    break;
                case Page.TYPE_STREAM_TRUNK:
                    typeName = "log trunk";
                    break;
                case Page.TYPE_STREAM_DATA:
                    typeName = "log data";
                    break;
                default:
                    typeName = "ERROR: unknown type " + type;
                    break;
            }
            writer.println("-- undo page " + pageId + " " + typeName);
            if (trace) {
                Data d = Data.create(null, data);
                dumpPage(writer, d, pageId, pageCount);
            }
        } else if (x == PageLog.ADD) {
            int sessionId = in.readVarInt();
            setStorage(in.readVarInt());
            Row row = PageLog.readRow(RowFactory.DEFAULT, in, s);
            writer.println("-- session " + sessionId + " table " + storageId + " + " + row.toString());
            if (transactionLog) {
                if (storageId == 0 && row.getColumnCount() >= 4) {
                    int tableId = (int) row.getKey();
                    String sql = row.getValue(3).getString();
                    String name = extractTableOrViewName(sql);
                    if (row.getValue(2).getInt() == DbObject.TABLE_OR_VIEW) {
                        tableMap.put(tableId, name);
                    }
                    writer.println(sql + ";");
                } else {
                    String tableName = tableMap.get(storageId);
                    if (tableName != null) {
                        StatementBuilder buff = new StatementBuilder();
                        buff.append("INSERT INTO ").append(tableName).append(" VALUES(");
                        for (int i = 0; i < row.getColumnCount(); i++) {
                            buff.appendExceptFirst(", ");
                            buff.append(row.getValue(i).getSQL());
                        }
                        buff.append(");");
                        writer.println(buff.toString());
                    }
                }
            }
        } else if (x == PageLog.REMOVE) {
            int sessionId = in.readVarInt();
            setStorage(in.readVarInt());
            long key = in.readVarLong();
            writer.println("-- session " + sessionId + " table " + storageId + " - " + key);
            if (transactionLog) {
                if (storageId == 0) {
                    int tableId = (int) key;
                    String tableName = tableMap.get(tableId);
                    if (tableName != null) {
                        writer.println("DROP TABLE IF EXISTS " + tableName + ";");
                    }
                } else {
                    String tableName = tableMap.get(storageId);
                    if (tableName != null) {
                        String sql = "DELETE FROM " + tableName + " WHERE _ROWID_ = " + key + ";";
                        writer.println(sql);
                    }
                }
            }
        } else if (x == PageLog.TRUNCATE) {
            int sessionId = in.readVarInt();
            setStorage(in.readVarInt());
            writer.println("-- session " + sessionId + " table " + storageId + " truncate");
            if (transactionLog) {
                writer.println("TRUNCATE TABLE " + storageId);
            }
        } else if (x == PageLog.COMMIT) {
            int sessionId = in.readVarInt();
            writer.println("-- commit " + sessionId);
        } else if (x == PageLog.ROLLBACK) {
            int sessionId = in.readVarInt();
            writer.println("-- rollback " + sessionId);
        } else if (x == PageLog.PREPARE_COMMIT) {
            int sessionId = in.readVarInt();
            String transaction = in.readString();
            writer.println("-- prepare commit " + sessionId + " " + transaction);
        } else if (x == PageLog.NOOP) {
        // nothing to do
        } else if (x == PageLog.CHECKPOINT) {
            writer.println("-- checkpoint");
        } else if (x == PageLog.FREE_LOG) {
            int size = in.readVarInt();
            StringBuilder buff = new StringBuilder("-- free");
            for (int i = 0; i < size; i++) {
                buff.append(' ').append(in.readVarInt());
            }
            writer.println(buff);
        } else {
            writer.println("-- ERROR: unknown operation " + x);
            break;
        }
    }
}
Also used : DataReader(org.h2.store.DataReader) CompressLZF(org.h2.compress.CompressLZF) StatementBuilder(org.h2.util.StatementBuilder) Data(org.h2.store.Data) Row(org.h2.result.Row) SimpleRow(org.h2.result.SimpleRow)

Example 39 with Page

use of org.h2.store.Page in project h2database by h2database.

the class PageLog method recover.

/**
 * Run one recovery stage. There are three recovery stages: 0: only the undo
 * steps are run (restoring the state before the last checkpoint). 1: the
 * pages that are used by the transaction log are allocated. 2: the
 * committed operations are re-applied.
 *
 * @param stage the recovery stage
 * @return whether the transaction log was empty
 */
boolean recover(int stage) {
    if (trace.isDebugEnabled()) {
        trace.debug("log recover stage: " + stage);
    }
    if (stage == RECOVERY_STAGE_ALLOCATE) {
        PageInputStream in = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
        usedLogPages = in.allocateAllPages();
        in.close();
        return true;
    }
    PageInputStream pageIn = new PageInputStream(store, logKey, firstTrunkPage, firstDataPage);
    DataReader in = new DataReader(pageIn);
    int logId = 0;
    Data data = store.createData();
    boolean isEmpty = true;
    try {
        int pos = 0;
        while (true) {
            int x = in.readByte();
            if (x < 0) {
                break;
            }
            pos++;
            isEmpty = false;
            if (x == UNDO) {
                int pageId = in.readVarInt();
                int size = in.readVarInt();
                if (size == 0) {
                    in.readFully(data.getBytes(), store.getPageSize());
                } else if (size == 1) {
                    // empty
                    Arrays.fill(data.getBytes(), 0, store.getPageSize(), (byte) 0);
                } else {
                    in.readFully(compressBuffer, size);
                    try {
                        compress.expand(compressBuffer, 0, size, data.getBytes(), 0, store.getPageSize());
                    } catch (ArrayIndexOutOfBoundsException e) {
                        DbException.convertToIOException(e);
                    }
                }
                if (stage == RECOVERY_STAGE_UNDO) {
                    if (!undo.get(pageId)) {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log undo {0}", pageId);
                        }
                        store.writePage(pageId, data);
                        undo.set(pageId);
                        undoAll.set(pageId);
                    } else {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log undo skip {0}", pageId);
                        }
                    }
                }
            } else if (x == ADD) {
                int sessionId = in.readVarInt();
                int tableId = in.readVarInt();
                Row row = readRow(store.getDatabase().getRowFactory(), in, data);
                if (stage == RECOVERY_STAGE_UNDO) {
                    store.allocateIfIndexRoot(pos, tableId, row);
                } else if (stage == RECOVERY_STAGE_REDO) {
                    if (isSessionCommitted(sessionId, logId, pos)) {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log redo + table: " + tableId + " s: " + sessionId + " " + row);
                        }
                        store.redo(tableId, row, true);
                    } else {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log ignore s: " + sessionId + " + table: " + tableId + " " + row);
                        }
                    }
                }
            } else if (x == REMOVE) {
                int sessionId = in.readVarInt();
                int tableId = in.readVarInt();
                long key = in.readVarLong();
                if (stage == RECOVERY_STAGE_REDO) {
                    if (isSessionCommitted(sessionId, logId, pos)) {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log redo - table: " + tableId + " s:" + sessionId + " key: " + key);
                        }
                        store.redoDelete(tableId, key);
                    } else {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log ignore s: " + sessionId + " - table: " + tableId + " " + key);
                        }
                    }
                }
            } else if (x == TRUNCATE) {
                int sessionId = in.readVarInt();
                int tableId = in.readVarInt();
                if (stage == RECOVERY_STAGE_REDO) {
                    if (isSessionCommitted(sessionId, logId, pos)) {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log redo truncate table: " + tableId);
                        }
                        store.redoTruncate(tableId);
                    } else {
                        if (trace.isDebugEnabled()) {
                            trace.debug("log ignore s: " + sessionId + " truncate table: " + tableId);
                        }
                    }
                }
            } else if (x == PREPARE_COMMIT) {
                int sessionId = in.readVarInt();
                String transaction = in.readString();
                if (trace.isDebugEnabled()) {
                    trace.debug("log prepare commit " + sessionId + " " + transaction + " pos: " + pos);
                }
                if (stage == RECOVERY_STAGE_UNDO) {
                    int page = pageIn.getDataPage();
                    setPrepareCommit(sessionId, page, transaction);
                }
            } else if (x == ROLLBACK) {
                int sessionId = in.readVarInt();
                if (trace.isDebugEnabled()) {
                    trace.debug("log rollback " + sessionId + " pos: " + pos);
                }
            // ignore - this entry is just informational
            } else if (x == COMMIT) {
                int sessionId = in.readVarInt();
                if (trace.isDebugEnabled()) {
                    trace.debug("log commit " + sessionId + " pos: " + pos);
                }
                if (stage == RECOVERY_STAGE_UNDO) {
                    setLastCommitForSession(sessionId, logId, pos);
                }
            } else if (x == NOOP) {
            // nothing to do
            } else if (x == CHECKPOINT) {
                logId++;
            } else if (x == FREE_LOG) {
                int count = in.readVarInt();
                for (int i = 0; i < count; i++) {
                    int pageId = in.readVarInt();
                    if (stage == RECOVERY_STAGE_REDO) {
                        if (!usedLogPages.get(pageId)) {
                            store.free(pageId, false);
                        }
                    }
                }
            } else {
                if (trace.isDebugEnabled()) {
                    trace.debug("log end");
                    break;
                }
            }
        }
    } catch (DbException e) {
        if (e.getErrorCode() == ErrorCode.FILE_CORRUPTED_1) {
            trace.debug("log recovery stopped");
        } else {
            throw e;
        }
    } catch (IOException e) {
        trace.debug("log recovery completed");
    }
    undo = new BitSet();
    if (stage == RECOVERY_STAGE_REDO) {
        usedLogPages = null;
    }
    return isEmpty;
}
Also used : BitSet(java.util.BitSet) Row(org.h2.result.Row) IOException(java.io.IOException) DbException(org.h2.message.DbException)

Example 40 with Page

use of org.h2.store.Page in project h2database by h2database.

the class PageStore method compact.

/**
 * Shrink the file so there are no empty pages at the end.
 *
 * @param compactMode 0 if no compacting should happen, otherwise
 * TransactionCommand.SHUTDOWN_COMPACT or TransactionCommand.SHUTDOWN_DEFRAG
 */
public synchronized void compact(int compactMode) {
    if (!database.getSettings().pageStoreTrim) {
        return;
    }
    if (SysProperties.MODIFY_ON_WRITE && readMode && compactMode == 0) {
        return;
    }
    openForWriting();
    // find the last used page
    int lastUsed = -1;
    for (int i = getFreeListId(pageCount); i >= 0; i--) {
        lastUsed = getFreeList(i).getLastUsed();
        if (lastUsed != -1) {
            break;
        }
    }
    // open a new log at the very end
    // (to be truncated later)
    writeBack();
    log.free();
    recoveryRunning = true;
    try {
        logFirstTrunkPage = lastUsed + 1;
        allocatePage(logFirstTrunkPage);
        log.openForWriting(logFirstTrunkPage, true);
        // ensure the free list is backed up again
        log.checkpoint();
    } finally {
        recoveryRunning = false;
    }
    long start = System.nanoTime();
    boolean isCompactFully = compactMode == CommandInterface.SHUTDOWN_COMPACT;
    boolean isDefrag = compactMode == CommandInterface.SHUTDOWN_DEFRAG;
    if (database.getSettings().defragAlways) {
        isCompactFully = isDefrag = true;
    }
    int maxCompactTime = database.getSettings().maxCompactTime;
    int maxMove = database.getSettings().maxCompactCount;
    if (isCompactFully || isDefrag) {
        maxCompactTime = Integer.MAX_VALUE;
        maxMove = Integer.MAX_VALUE;
    }
    int blockSize = isCompactFully ? COMPACT_BLOCK_SIZE : 1;
    int firstFree = MIN_PAGE_COUNT;
    for (int x = lastUsed, j = 0; x > MIN_PAGE_COUNT && j < maxMove; x -= blockSize) {
        for (int full = x - blockSize + 1; full <= x; full++) {
            if (full > MIN_PAGE_COUNT && isUsed(full)) {
                synchronized (this) {
                    firstFree = getFirstFree(firstFree);
                    if (firstFree == -1 || firstFree >= full) {
                        j = maxMove;
                        break;
                    }
                    if (compact(full, firstFree)) {
                        j++;
                        long now = System.nanoTime();
                        if (now > start + TimeUnit.MILLISECONDS.toNanos(maxCompactTime)) {
                            j = maxMove;
                            break;
                        }
                    }
                }
            }
        }
    }
    if (isDefrag) {
        log.checkpoint();
        writeBack();
        cache.clear();
        ArrayList<Table> tables = database.getAllTablesAndViews(false);
        recordedPagesList = New.arrayList();
        recordedPagesIndex = new IntIntHashMap();
        recordPageReads = true;
        Session sysSession = database.getSystemSession();
        for (Table table : tables) {
            if (!table.isTemporary() && TableType.TABLE == table.getTableType()) {
                Index scanIndex = table.getScanIndex(sysSession);
                Cursor cursor = scanIndex.find(sysSession, null, null);
                while (cursor.next()) {
                    cursor.get();
                }
                for (Index index : table.getIndexes()) {
                    if (index != scanIndex && index.canScan()) {
                        cursor = index.find(sysSession, null, null);
                        while (cursor.next()) {
                        // the data is already read
                        }
                    }
                }
            }
        }
        recordPageReads = false;
        int target = MIN_PAGE_COUNT - 1;
        int temp = 0;
        for (int i = 0, size = recordedPagesList.size(); i < size; i++) {
            log.checkpoint();
            writeBack();
            int source = recordedPagesList.get(i);
            Page pageSource = getPage(source);
            if (!pageSource.canMove()) {
                continue;
            }
            while (true) {
                Page pageTarget = getPage(++target);
                if (pageTarget == null || pageTarget.canMove()) {
                    break;
                }
            }
            if (target == source) {
                continue;
            }
            temp = getFirstFree(temp);
            if (temp == -1) {
                DbException.throwInternalError("no free page for defrag");
            }
            cache.clear();
            swap(source, target, temp);
            int index = recordedPagesIndex.get(target);
            if (index != IntIntHashMap.NOT_FOUND) {
                recordedPagesList.set(index, source);
                recordedPagesIndex.put(source, index);
            }
            recordedPagesList.set(i, target);
            recordedPagesIndex.put(target, i);
        }
        recordedPagesList = null;
        recordedPagesIndex = null;
    }
    // TODO can most likely be simplified
    checkpoint();
    log.checkpoint();
    writeIndexRowCounts();
    log.checkpoint();
    writeBack();
    commit(pageStoreSession);
    writeBack();
    log.checkpoint();
    log.free();
    // truncate the log
    recoveryRunning = true;
    try {
        setLogFirstPage(++logKey, 0, 0);
    } finally {
        recoveryRunning = false;
    }
    writeBack();
    for (int i = getFreeListId(pageCount); i >= 0; i--) {
        lastUsed = getFreeList(i).getLastUsed();
        if (lastUsed != -1) {
            break;
        }
    }
    int newPageCount = lastUsed + 1;
    if (newPageCount < pageCount) {
        freed.set(newPageCount, pageCount, false);
    }
    pageCount = newPageCount;
    // the easiest way to remove superfluous entries
    freeLists.clear();
    trace.debug("pageCount: " + pageCount);
    long newLength = (long) pageCount << pageSizeShift;
    if (file.length() != newLength) {
        file.setLength(newLength);
        writeCount++;
    }
}
Also used : IntIntHashMap(org.h2.util.IntIntHashMap) RegularTable(org.h2.table.RegularTable) Table(org.h2.table.Table) Index(org.h2.index.Index) PageIndex(org.h2.index.PageIndex) PageDelegateIndex(org.h2.index.PageDelegateIndex) MultiVersionIndex(org.h2.index.MultiVersionIndex) PageBtreeIndex(org.h2.index.PageBtreeIndex) PageDataIndex(org.h2.index.PageDataIndex) Cursor(org.h2.index.Cursor) Session(org.h2.engine.Session)

Aggregations

CreateTableData (org.h2.command.ddl.CreateTableData)8 Page (org.h2.mvstore.Page)7 Data (org.h2.store.Data)7 Column (org.h2.table.Column)5 IndexColumn (org.h2.table.IndexColumn)5 Value (org.h2.value.Value)5 MVStore (org.h2.mvstore.MVStore)4 Row (org.h2.result.Row)4 SearchRow (org.h2.result.SearchRow)4 IOException (java.io.IOException)3 Connection (java.sql.Connection)3 CRC32 (java.util.zip.CRC32)3 PageBtreeIndex (org.h2.index.PageBtreeIndex)3 PageDataIndex (org.h2.index.PageDataIndex)3 PageIndex (org.h2.index.PageIndex)3 DbException (org.h2.message.DbException)3 Page (org.h2.store.Page)3 ValueString (org.h2.value.ValueString)3 PrintWriter (java.io.PrintWriter)2 ResultSet (java.sql.ResultSet)2