/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
*/
package org.chaidb.db.transaction;
import org.apache.log4j.Logger;
import org.chaidb.db.DbEnvironment;
import org.chaidb.db.exception.ChaiDBException;
import org.chaidb.db.helper.AbstractDaemonThread;
import org.chaidb.db.index.btree.bufmgr.PageBufferManager;
import org.chaidb.db.log.LogManager;
import org.chaidb.db.log.Lsn;
public class CheckpointThread extends AbstractDaemonThread {
private static final Logger logger = Logger.getLogger(CheckpointThread.class);
private static PageBufferManager bpm = PageBufferManager.getInstance();
/* The transaction manager is responsible for managing the checkpoint thread. */
private TransactionManager txnManager;
private Checkpoint checkpoint;
/* The Lsn of the last checkpoint. */
private Lsn ckpLsn;
/* The checkpoint run mode or policy by tuning the below parameters.
* The kbyte kilobytes of log data have been written since the last checkpoint.
* The min minutes have passed since the last checkpoint.
* The flags parameter MUST be set one of the following values:
* TransactionManager.DB_PERIOD OR TransactionManager.DB_FORCE
*/
private int kbytes;
/* The checkpoint run mode or policy by tuning the below parameters.
* The kbyte kilobytes of log data have been written since the last checkpoint.
* The min minutes have passed since the last checkpoint.
* The flags parameter MUST be set one of the following values:
* TransactionManager.DB_PERIOD OR TransactionManager.DB_FORCE
*/
private int mins;
/* The checkpoint run mode or policy by tuning the below parameters.
* The kbyte kilobytes of log data have been written since the last checkpoint.
* The min minutes have passed since the last checkpoint.
* The flags parameter MUST be set one of the following values:
* TransactionManager.DB_PERIOD OR TransactionManager.DB_FORCE
*/
private int flags;
/* The lock manager just for blocking new transactions active when doing checkpoint. */
//private LockManager lockMgr;
public static final String CHECKPOINT_THREADNAME = "Checkpoint thread";
/**
* Constructor.
* Doing a checkpoint record to make the system state consistent - flushes the log buffer and underlying memory pool,
* and writes a checkpoint record to the log.
* <p/>
* If either kbytes or mins is non-zero, the checkpoint is only done if there has been
* activity since the last checkpoint and either more than min minutes have passed
* since the last checkpoint, or if more than kbyte kilobytes of log data have been written
* since the last checkpoint. If either kbytes or mins is non-zero, the flags MUST BE set to TransactionManager.DB_PERIOD.
* If both kbytes parameter and mins parameter is set to zero, and the flags is set to TransactionManager.DB_PERIOD,
* the system will not do checkpoint.
* If the flags is set to TransactionManager.DB_FORCE, in spite of whatever either kbytes or mins parameters is set.
* The system will force a checkpoint record even if there has been no activity since the last checkpoint.
* After doing a checkpoint, the
* Note: If the checkpoint thread intent to do checkpoint in 5 times, but still have some active transaction,
* the system will throw CHECKPOINT_OVERTIME exception.
* If the flags is set to TransactionManager.DB_SHUTDOWN, in spite of whatever either kbytes or mins parameters is set.
* The system will force a checkpoint record even if there has been no activity since the last checkpoint. After doing checkpoint
* the checkpoint thread will dead.
*
* @param txnManager The transaction manager is responsible for managing the checkpoint.
* @param kbytes The kbyte kilobytes of log data have been written since the last checkpoint.
* @param mins The min minutes have passed since the last checkpoint.
* @param flags The flags parameter MUST be set one of the following values:
* TransactionManager.DB_PERIOD OR TransactionManager.DB_FORCE OR TransactionManager.DB_SHUTDOWN
*/
public CheckpointThread(TransactionManager txnManager, int kbytes, int mins, int flags) {
super(CHECKPOINT_THREADNAME);
this.txnManager = txnManager;
this.txnManager.setTimeCkp(System.currentTimeMillis());
this.kbytes = kbytes;
this.mins = mins;
this.flags = flags;
this.checkpoint = new Checkpoint(txnManager, flags);
/* Initialize checkpoint LSN to 'zero'. */
ckpLsn = new Lsn(LogManager.FIRSTREC_LSN);
}
/**
* After kbyte kilobytes of log data is written since the last checkpoint, the system will do a checkpoint.
*
* @param kbytes The kbyte kilobytes of log data have been written since the last checkpoint.
*/
public void setKbytes(int kbytes) {
this.kbytes = kbytes;
}
/**
* After min minutes pass since the last checkpoint. the system will do a checkpoint.
*
* @param mins The min minutes have passed since the last checkpoint.
*/
public void setMins(int mins) {
this.mins = mins;
}
/**
* The flags parameter MUST be set one of the following values:
* TransactionManager.DB_PERIOD OR TransactionManager.DB_FORCE
*/
public void setFlags(int flags) {
if ((flags != TransactionManager.DB_FORCE) && (flags != TransactionManager.DB_PERIOD) && (flags != TransactionManager.DB_SHUTDOWN)) {
return;
}
this.flags = flags;
}
/**
* Forces the checkpoint thread to stop.
*/
public void setFinish() {
setOver();
}
/**
* four conditons to do checkpoint
* 1.flags ==TransactionManager.DB_FORCE
* 2.flags == TransactionManager.DB_SHUTDOWN
* 3.log bytes > kbytes
* 4.two checkpoint time distance > mins
*/
protected void runningBody() {
int mBytes;
int bytes;
long lastCkpTime;
long nowTime;
try {
boolean doFlag = false;
if ((flags == TransactionManager.DB_FORCE) || (flags == TransactionManager.DB_SHUTDOWN)) {
doFlag = true;
} else if (flags == TransactionManager.DB_PERIOD) {
/*
* We add the current buffer offset so as to count bytes that
* have not yet been written, but are sitting in the log buffer.
*/
mBytes = this.txnManager.getLogManager().getChkptMBytes();
bytes = this.txnManager.getLogManager().getChkptBytes();
if ((kbytes != 0) && (((mBytes * 1024) + (bytes / 1024)) >= kbytes)) {
//bytes size
doFlag = true;
} else if (mins != 0) { //time distance
nowTime = System.currentTimeMillis();
/* time of last checkpoint */
lastCkpTime = this.txnManager.getTimeCkp();
if (((nowTime - lastCkpTime) / 1000) >= (long) (mins * 60)) {
doFlag = true;
}
}
}
/* if reaching condition, do fuzzy checkpoint */
if (doFlag && (!DbEnvironment.READ_ONLY)) {
checkpoint.doCheckpoint(false);
}
} catch (ChaiDBException e) {
logger.error(e);
}
if (flags == TransactionManager.DB_SHUTDOWN) {
setOver();
} else {
/*
* If we checked time and data and didn't go to checkpoint,
* we're done.
*/
try {
sleep(10000);
} catch (InterruptedException e) {
return;
}
}
}
}