/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: OverflowPageStorage.java
 *
 * Copyright (c) 2009, Static Free Software. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.database.geometry.btree;

/**
 *  Combines two PageStorage objects, using the first until the "high
 *  water mark" is exceeded, then moving to the other.  Generally the
 *  first PageStorage is "small but fast" and the second is "large but
 *  slow".
 *
 *  Might not be thread-safe.
 */
public class OverflowPageStorage extends PageStorage {

    private final PageStorage ps1;
    private final PageStorage ps2;
    private final int highWaterMark;
    private boolean overflowed = false;

    /** Note that highWaterMark is in BYTES, not pages */
    public OverflowPageStorage(PageStorage ps1, PageStorage ps2, long highWaterMark) {
        super(Math.max(ps1.getPageSize(), ps1.getPageSize()));
        this.ps1 = ps1;
        this.ps2 = ps2;
        this.highWaterMark = (int)(highWaterMark / getPageSize());
    } 

    public int getNumPages() { return overflowed ? ps2.getNumPages() : ps1.getNumPages(); }
    public synchronized int createPage() {
        if (overflowed) return ps2.createPage();
        if (ps1.getNumPages() < highWaterMark) return ps1.createPage();
        byte[] buf = new byte[getPageSize()];
        for(int i=0; i<ps1.getNumPages(); i++) {
            while(ps2.getNumPages() < i+1) ps2.createPage();
            ps1.readPage(i, buf, 0);
            ps2.writePage(i, buf, 0);
        }
        overflowed = true;
        ps1.close();
        return ps2.createPage();
    }
    public void fsync(int pageid) { if (overflowed) ps2.fsync(pageid); else ps1.fsync(pageid); }
    public void writePage(int pageid, byte[] buf, int ofs) {
        if (overflowed) ps2.writePage(pageid, buf, ofs);
        else            ps1.writePage(pageid, buf, ofs);
    }
    public void readPage(int pageid, byte[] buf, int ofs) {
        if (overflowed) ps2.readPage(pageid, buf, ofs);
        else            ps1.readPage(pageid, buf, ofs);
    }

    public synchronized void close() { if (overflowed) ps2.close(); else ps1.close(); }
}
