package org.maachang.mimdb.core;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.maachang.mimdb.core.util.AtomicNumber;
import org.maachang.mimdb.core.util.AtomicNumber32;

/**
 * テーブル更新ロック.
 * 
 * @version 2013/10/14
 * @author masahito suzuki
 * @since MasterInMemDB 1.00
 */
public final class MimdbUpdateLock implements MimdbBase {
    
    protected MimdbUpdateLock() {}
    
    /**
     * DB更新ID.
     */
    private final AtomicNumber dbId = new AtomicNumber( 0L ) ;
    
    /**
     * ReadWriteロック用オブジェクト.
     */
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock() ;
    
    /**
     * ロック状態.
     */
    private AtomicNumber32 readFlag = new AtomicNumber32( 0 ) ;
    private AtomicNumber32 writeFlag = new AtomicNumber32( 0 ) ;
    
    /**
     * 現在のDB更新IDを取得.
     * @return long DB更新IDが返却されます.
     */
    public long getDbId() {
        return dbId.get() ;
    }
    
    /**
     * 現在のDB更新IDを更新.
     * @return long 新しいDB更新IDが返却されます.
     */
    public long update() {
        return dbId.inc() ;
    }
    
    /**
     * 現在のDB更新IDを変更.
     * @param id 変更するIDを設定します.
     */
    public void setDbId( long id ) {
        dbId.set( id ) ;
    }
    
    /**
     * 書き込み専用ロック開始.
     */
    public void writeBegin() {
        rwLock.writeLock().lock() ;
        writeFlag.inc() ;
    }
    
    /**
     * 書き込み専用ロック解除.
     */
    public void writeEnd() {
        rwLock.writeLock().unlock() ;
        writeFlag.dec() ;
    }
    
    /**
     * 読み込み専用ロック.
     */
    public void readBegin() {
        rwLock.readLock().lock() ;
        readFlag.inc() ;
    }
    
    /**
     * 読み込み専用ロック解除.
     */
    public void readEnd() {
        rwLock.readLock().unlock() ;
        readFlag.dec() ;
    }
    
    /**
     * 書き込みロック中かチェック.
     * @return boolean [true]の場合、書き込みロックがされています.
     */
    public boolean isWriteLock() {
        return writeFlag.get() > 0L ;
    }
    
    /**
     * 読み込みロック中かチェック.
     * @return boolean [true]の場合、書き込みロックがされています.
     */
    public boolean isReadLock() {
        return readFlag.get() > 0L ;
    }
    
}

