⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 storeimpl.java

📁 這是一個油Java實作的資料庫系統 是個入門的好材料
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/* =============================================================
 * SmallSQL : a free Java DBMS library for the Java(tm) platform
 * =============================================================
 *
 * (C) Copyright 2004-2007, by Volker Berlin.
 *
 * Project Info:  http://www.smallsql.de/
 *
 * This library 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 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library 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 Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 *
 * ---------------
 * StoreImpl.java
 * ---------------
 * Author: Volker Berlin
 * 
 */
package smallsql.database;

import java.io.*;
import java.sql.SQLException;
import smallsql.database.language.Language;

public class StoreImpl extends Store {

    private static final int DEFAULT_PAGE_SIZE = 8192; // 8 Kb
	private static final int PAGE_MAGIC = 0x12DD13DE; // are used for repairing a table
    /**
     * The structure of the Page Control Block is:
     * 4 byte - page magic
     * 4 Byte - Status 0:normal; 1:deleted; 2:Pointer to an update; 3: updated page
     * 4 Byte - used size of the page
     * 4 byte - physical size of the page
     * 4 byte - offset to the next page
     * 8 byte - position of an updated page
     */
	private static final int PAGE_CONTROL_SIZE = 28;
	private static final byte[] page_control = new byte[PAGE_CONTROL_SIZE]; 
	private int status; // valid value are follow:
	private static final int NORMAL = 0;
    private static final int DELETED = 1;
    /**
     * Using of UPDATE_POINTER and UPDATED_PAGE
     * 	If a page are updated and the new data are larger as the old data then
     *  the old page are changed to a UPDATE_POINTER. The new page is 
     *  a UPDATED_PAGE. On reading the pages only the UPDATE_POINTER is read.
     *  The UPDATED_PAGE are skipped. Thats a row change not it position.
     */
	private static final int UPDATE_POINTER = 2;
	private static final int UPDATED_PAGE = 3;
    
    final private Table table;
    private byte[] page; // Data of one page
    private StorePage storePage;
    private long filePos; // Position in the file
    private int sizeUsed;
    private int sizePhysical;
    private int nextPageOffset;
    private long filePosUpdated;
    private int type;
    
    private StoreImpl updatePointer;

    private StoreImpl( Table table, StorePage storePage, int type, long filePos ){
		this.table     = table;
		this.storePage    = storePage;
		this.filePos   = filePos;
		this.type      = type;
    }
    
    
    /**
     * Follow types of StoreImpl are possible:
     * INSERT: A page that will be include new data. filePos is not define yet.
     * CREATE: A special type of INSERT
     * SELECT: Only read operations are possible.
     * UPDATE: Has a filePos, if the new size is to small then the old page must be deleted and a new added.
     * DELETE: Has no cache else only the filePos to write the flag.
    */
    static StoreImpl createStore( Table table, StorePage storePage, int type, long filePos ) throws SQLException{
        try {
            StoreImpl store = new StoreImpl(table, storePage, type, filePos);
            RandomAccessFile raFile = storePage.raFile;
            switch(type){
                case SQLTokenizer.LONGVARBINARY:
                    // wird verwendet zum speichern von LONGVARBINARY und LONGVARCHAR
                    store.page = new byte[(int)filePos + PAGE_CONTROL_SIZE];
                    store.filePos = -1;
                    break;
                case SQLTokenizer.INSERT:
                case SQLTokenizer.CREATE:
                    store.page = new byte[DEFAULT_PAGE_SIZE];
                    break;
                case SQLTokenizer.SELECT:
                case SQLTokenizer.UPDATE:
            	case SQLTokenizer.DELETE:
                    if(storePage.page == null){
                        if(filePos >= raFile.length()-PAGE_CONTROL_SIZE){
                            return null;
                        }
                        raFile.seek(filePos);
                        synchronized(page_control){
                        	raFile.read(page_control);
            				store.page = page_control;
            				store.readPageHeader();
                        }
                        store.page = new byte[store.sizeUsed];
                        raFile.seek(filePos);
                        raFile.read(store.page);
                    }else{
                        store.page = storePage.page;
                        store.readPageHeader();
                    }
                    store = store.loadUpdatedStore();
                    break;
                default: throw new Error();
            }
            store.offset = PAGE_CONTROL_SIZE;
            return store;
        } catch (Throwable th) {
            throw SmallSQLException.createFromException(th);
        }
    }
    
    
    /**
     * Recreate a StoreImpl from an uncommitted StorePage.
     */
	static StoreImpl recreateStore( Table table, StorePage storePage, int type) throws Exception{
		StoreImpl store = new StoreImpl(table, storePage, type, -1);
		store.page = storePage.page;
		store.readPageHeader();
		store = store.loadUpdatedStore();
		store.offset = PAGE_CONTROL_SIZE;
		return store;
	}
	
    
    private final void readPageHeader() throws SQLException{
		if(readInt() != PAGE_MAGIC)
			throw SmallSQLException.create(Language.TABLE_CORRUPT_PAGE, new Object[] { new Long(filePos) });
		status = readInt();
		sizeUsed  = readInt();
		sizePhysical = readInt();
		nextPageOffset = readInt();
		filePosUpdated = readLong();
    }
    
    
	final private StoreImpl loadUpdatedStore() throws Exception{
		if(status != UPDATE_POINTER) return this;
		StoreImpl storeTemp = table.getStore( ((TableStorePage)storePage).con, filePosUpdated, type);
		storeTemp.updatePointer = this;
		return storeTemp;
    }
    

    private void resizePage(int minNewSize){
    	int newSize = Math.max(minNewSize, page.length*2);
    	byte[] newPage = new byte[newSize];
    	System.arraycopy( page, 0, newPage, 0, page.length);
    	page = newPage;
    }
    

	boolean isValidPage(){
		return status == NORMAL || (status == UPDATED_PAGE && updatePointer != null); 
	}
	
    int getUsedSize(){
        return sizeUsed;
    }
    
    long getNextPagePos(){
    	if(updatePointer != null) return updatePointer.getNextPagePos();
    	if(nextPageOffset <= 0){
			nextPageOffset = sizePhysical; 
    	}
		return filePos + nextPageOffset;
    }

    
    /**
     * 
     * @param con Is needed to add this page to the commitPages. If it null then it save directly without rollback option.
     * @return The file position if con == null.
     * @throws SQLException
     */
    long writeFinsh(SSConnection con) throws SQLException{
        switch(type){
            case SQLTokenizer.LONGVARBINARY:
            case SQLTokenizer.INSERT:
            case SQLTokenizer.CREATE:
                sizeUsed = sizePhysical = offset;
                break;
			case SQLTokenizer.UPDATE:
				if(status != UPDATE_POINTER) {
					sizeUsed = offset;
					break;
				}
            case SQLTokenizer.DELETE:
				sizeUsed = PAGE_CONTROL_SIZE;
                break;
            //SQLTokenizer.SELECT should not occur here
            default: throw new Error(""+type);
        }
		offset = 0;
		writeInt( PAGE_MAGIC ); // for repair 
		writeInt( status);
		writeInt( sizeUsed );
		writeInt( sizePhysical );
		writeInt( 0 ); //nextPageOffset
		writeLong( filePosUpdated ); // Pointer of an updated page
		storePage.setPageData( page, sizeUsed ); //TODO page sollte eigentlich beim einlesen gesetzt sein
        if(con == null){
        	// the pointer is needed to safe in another page
        	// this produce not referenced pages on rollback
			return storePage.commit();
        }else{
            return 0;
        }
    }
    
    
    final private void createWriteLock() throws SQLException{
		TableStorePage storePageWrite = table.requestWriteLock( ((TableStorePage)storePage).con, (TableStorePage)storePage );
		if(storePageWrite == null)
			throw SmallSQLException.create(Language.ROW_LOCKED);
		storePage = storePageWrite;
    }
    
    /**
     * Is call from updateRow().
     * The offset of newData must be at the end of the data. It used as new page size. 
     */
	void updateFinsh(SSConnection con, StoreImpl newData) throws SQLException{
		type = SQLTokenizer.UPDATE;
		createWriteLock();
		if(newData.offset <= sizePhysical || filePos == -1){
			// the old page can be overwrite because it it large enough
			page = newData.page; //newData is only a temp StoreImpl
			offset = newData.offset;
			if(sizePhysical < offset) sizePhysical = offset; // occur only on updates of not commited inserts (filePos == -1
			writeFinsh(con);
		}else{
			// we need to create a new page because the old page is to small
			newData.status = UPDATED_PAGE;
			if(updatePointer == null){
				// we need to create a new page and change the old page to a UPDATE_POINTER
				((TableStorePage)newData.storePage).lockType = TableView.LOCK_INSERT;
				filePosUpdated = newData.writeFinsh(null);
				status = UPDATE_POINTER;
			}else{
				// we need to create a new page and delete the old page
				((TableStorePage)newData.storePage).lockType = TableView.LOCK_INSERT;
				updatePointer.filePosUpdated = newData.writeFinsh(null);
				updatePointer.status = UPDATE_POINTER;
				updatePointer.type = SQLTokenizer.UPDATE;
				updatePointer.createWriteLock();
				updatePointer.writeFinsh(con);
				status = DELETED;
			}
			writeFinsh(con);
		}
	}
    
/*==============================================================================

Write und Read Methoden

==============================================================================*/
    private int offset; // aktuelle read/write Position in der Page
	
	
	int getCurrentOffsetInPage(){
		return offset;
	}
	
	
	void setCurrentOffsetInPage(int newOffset){
		this.offset = newOffset;
	}
	

    void writeByte( int value ){
    	int newSize = offset + 1;
        if(newSize > page.length) resizePage(newSize);

        page[ offset++ ] = (byte)(value);
    }

    int readByte(){
        return page[ offset++ ];
    }

    int readUnsignedByte(){
        return page[ offset++ ] & 0xFF;
    }

    void writeBoolean( boolean value ){
    	int newSize = offset + 1;
        if(newSize > page.length) resizePage(newSize);

        page[ offset++ ] = (byte)(value ? 1 : 0);
    }

    boolean readBoolean(){
        return page[ offset++ ] != 0;
    }

    void writeShort( int value ){
    	int newSize = offset + 2;
        if(newSize > page.length) resizePage(newSize);

        page[ offset++ ] = (byte)(value >> 8);
        page[ offset++ ] = (byte)(value);
    }

    int readShort(){
        return (page[ offset++ ] << 8) | (page[ offset++ ] & 0xFF);
    }

    void writeInt( int value ){
    	int newSize = offset + 4;
        if(newSize > page.length) resizePage(newSize);

        page[ offset++ ] = (byte)(value >> 24);
        page[ offset++ ] = (byte)(value >> 16);
        page[ offset++ ] = (byte)(value >> 8);
        page[ offset++ ] = (byte)(value);
    }

    int readInt(){
        return  ((page[ offset++ ]) << 24) |
                ((page[ offset++ ] & 0xFF) << 16) |
                ((page[ offset++ ] & 0xFF) << 8) |
                ((page[ offset++ ] & 0xFF));
    }

    void writeLong( long value ){
    	int newSize = offset + 8;
        if(newSize >= page.length) resizePage(newSize);

        page[ offset++ ] = (byte)(value >> 56);
        page[ offset++ ] = (byte)(value >> 48);
        page[ offset++ ] = (byte)(value >> 40);
        page[ offset++ ] = (byte)(value >> 32);
        page[ offset++ ] = (byte)(value >> 24);
        page[ offset++ ] = (byte)(value >> 16);
        page[ offset++ ] = (byte)(value >> 8);
        page[ offset++ ] = (byte)(value);
    }

    long readLong(){
        //return (((long)readInt()) << 32) | (readInt() & 0xFFFFFFFFL);
        return  ((long)(page[ offset++ ]) << 56) |
                ((long)(page[ offset++ ] & 0xFF) << 48) |
                ((long)(page[ offset++ ] & 0xFF) << 40) |
                ((long)(page[ offset++ ] & 0xFF) << 32) |
                ((long)(page[ offset++ ] & 0xFF) << 24) |
                ((page[ offset++ ] & 0xFF) << 16) |

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -