h2/src/main/org/h2/mvstore/MVStore.java
/**
     * Revert to the beginning of the given version. All later changes (stored
     * or not) are forgotten. All maps that were created later are closed. A
     * rollback to a version before the last stored version is immediately
     * persisted. Rollback to version 0 means all data is removed.
     *
     * @param version the version to revert to
     */
Revert to the beginning of the given version. All later changes (stored
or not) are forgotten. All maps that were created later are closed. A
rollback to a version before the last stored version is immediately
persisted. Rollback to version 0 means all data is removed.

@param version the version to revert to
Revert to the beginning of the given version . All later changes ( stored or not ) are forgotten . All maps that were created later are closed . A rollback to a version before the last stored version is immediately persisted . Rollback to version 0 means all data is removed . @param version the version to revert to
public synchronized void rollbackTo(long version) {
        checkOpen();
        if (version == 0) {
            for (MVMap<?, ?> m : maps.values()) {
                m.close();
            }
            meta.clear();
            chunks.clear();
            if (fileStore != null) {
                fileStore.clear();
            }
            maps.clear();
            freedPageSpace.clear();
            currentVersion = version;
            setWriteVersion(version);
            metaChanged = false;
            return;
        }
        DataUtils.checkArgument(
                isKnownVersion(version),
                "Unknown version {0}", version);
        for (MVMap<?, ?> m : maps.values()) {
            m.rollbackTo(version);
        }
        for (long v = currentVersion; v >= version; v--) {
            if (freedPageSpace.size() == 0) {
                break;
            }
            freedPageSpace.remove(v);
        }
        meta.rollbackTo(version);
        metaChanged = false;
        boolean loadFromFile = false;
        int removeChunksNewerThan = -1;
        for (int chunkId = lastChunkId;; chunkId--) {
            Chunk x = chunks.get(chunkId);
            if (x == null) {
                break;
            } else if (x.version >= version) {
                removeChunksNewerThan = x.id;
            }
        }
        if (removeChunksNewerThan >= 0 && lastChunkId > removeChunksNewerThan) {
            revertTemp(version);
            loadFromFile = true;
            Chunk last = null;
            while (true) {
                last = chunks.get(lastChunkId);
                if (last == null) {
                    break;
                } else if (last.id <= removeChunksNewerThan) {
                    break;
                }
                chunks.remove(lastChunkId);
                int len = MathUtils.roundUpInt(last.length, BLOCK_SIZE) + BLOCK_SIZE;
                fileStore.free(last.start, len);
                lastChunkId--;
            }
            rootChunkStart = last.start;
            writeStoreHeader();
            byte[] bytes = getStoreHeaderBytes();
            ByteBuffer header = ByteBuffer.allocate(BLOCK_SIZE);
            header.put(bytes);
            header.rewind();
            fileStore.writeFully(fileStore.size(), header);
            readStoreHeader();
            readMeta();
        }
        for (MVMap<?, ?> m : New.arrayList(maps.values())) {
            int id = m.getId();
            if (m.getCreateVersion() >= version) {
                m.close();
                maps.remove(id);
            } else {
                if (loadFromFile) {
                    String r = meta.get("root." + id);
                    long root = r == null ? 0 : Long.parseLong(r);
                    m.setRootPos(root, -1);
                }
            }
        }
        Chunk c = chunks.get(lastChunkId - 1);
        if (c != null) {
            meta.put("chunk." + c.id, c.asString());
        }
        currentVersion = version;
        setWriteVersion(version);
    }
public synchronized void rollbackTo ( long version ) { checkOpen ( ) ; if ( version == 0 ) { for ( MVMap < ? , ? > m : maps . values ( ) ) { m . close ( ) ; } meta . clear ( ) ; chunks . clear ( ) ; if ( fileStore != null ) { fileStore . clear ( ) ; } maps . clear ( ) ; freedPageSpace . clear ( ) ; currentVersion = version ; setWriteVersion ( version ) ; metaChanged = false ; return ; } DataUtils . checkArgument ( isKnownVersion ( version ) , "Unknown version {0}" , version ) ; for ( MVMap < ? , ? > m : maps . values ( ) ) { m . rollbackTo ( version ) ; } for ( long v = currentVersion ; v >= version ; v -- ) { if ( freedPageSpace . size ( ) == 0 ) { break ; } freedPageSpace . remove ( v ) ; } meta . rollbackTo ( version ) ; metaChanged = false ; boolean loadFromFile = false ; int removeChunksNewerThan = - 1 ; for ( int chunkId = lastChunkId ; ; chunkId -- ) { Chunk x = chunks . get ( chunkId ) ; if ( x == null ) { break ; } else if ( x . version >= version ) { removeChunksNewerThan = x . id ; } } if ( removeChunksNewerThan >= 0 && lastChunkId > removeChunksNewerThan ) { revertTemp ( version ) ; loadFromFile = true ; Chunk last = null ; while ( true ) { last = chunks . get ( lastChunkId ) ; if ( last == null ) { break ; } else if ( last . id <= removeChunksNewerThan ) { break ; } chunks . remove ( lastChunkId ) ; int len = MathUtils . roundUpInt ( last . length , BLOCK_SIZE ) + BLOCK_SIZE ; fileStore . free ( last . start , len ) ; lastChunkId -- ; } rootChunkStart = last . start ; writeStoreHeader ( ) ; byte [ ] bytes = getStoreHeaderBytes ( ) ; ByteBuffer header = ByteBuffer . allocate ( BLOCK_SIZE ) ; header . put ( bytes ) ; header . rewind ( ) ; fileStore . writeFully ( fileStore . size ( ) , header ) ; readStoreHeader ( ) ; readMeta ( ) ; } for ( MVMap < ? , ? > m : New . arrayList ( maps . values ( ) ) ) { int id = m . getId ( ) ; if ( m . getCreateVersion ( ) >= version ) { m . close ( ) ; maps . remove ( id ) ; } else { if ( loadFromFile ) { String r = meta . get ( "root." + id ) ; long root = r == null ? 0 : Long . parseLong ( r ) ; m . setRootPos ( root , - 1 ) ; } } } Chunk c = chunks . get ( lastChunkId - 1 ) ; if ( c != null ) { meta . put ( "chunk." + c . id , c . asString ( ) ) ; } currentVersion = version ; setWriteVersion ( version ) ; }
Revert to the beginning of the given version.
Revert to the beginning of the given version .
// special case: remove all data // get the largest chunk with a version // higher or equal the requested version // need to write the header at the end of the file as well, // so that the old end header is not used // rollback might have rolled back the stored chunk metadata as well