如何确定Java中数据库页面的内容何时被更改?
所以我有一个simpleDB数据库,它是用Java编写的多用户事务数据库服务器,通过JDBC与Java客户机程序交互。问题是,我的文件管理器中的flush函数基本上是将数据写入a块的,它有不必要的调用,因此我需要一个标志,它基本上检查页面是否已被修改但未刷新到磁盘,然后刷新它,否则忽略。我的问题是,如果页面实际上是用多种方法修改的,我会感到困惑 我已经修改了一个变量来检查这一点。对我来说最明显的地方是appendval()函数,因为页面显然正在更改。但很明显,还有其他地方的页面正在被更改,我不知道在哪里如何确定Java中数据库页面的内容何时被更改?,java,database,Java,Database,所以我有一个simpleDB数据库,它是用Java编写的多用户事务数据库服务器,通过JDBC与Java客户机程序交互。问题是,我的文件管理器中的flush函数基本上是将数据写入a块的,它有不必要的调用,因此我需要一个标志,它基本上检查页面是否已被修改但未刷新到磁盘,然后刷新它,否则忽略。我的问题是,如果页面实际上是用多种方法修改的,我会感到困惑 我已经修改了一个变量来检查这一点。对我来说最明显的地方是appendval()函数,因为页面显然正在更改。但很明显,还有其他地方的页面正在被更改,我不知
public class LogMgr implements Iterable<BasicLogRecord> {
/**
* The location where the pointer to the last integer in the page is.
* A value of 0 means that the pointer is the first value in the page.
*/
public static final int LAST_POS = 0;
private String logfile;
private Page mypage = new Page();
private Block currentblk;
private int currentpos;
private int increment = 0;
private boolean wasModified = false;
/**
* Creates the manager for the specified log file.
* If the log file does not yet exist, it is created
* with an empty first block.
* This constructor depends on a {@link FileMgr} object
* that it gets from the method
* {@link simpledb.server.SimpleDB#fileMgr()}.
* That object is created during system initialization.
* Thus this constructor cannot be called until
* {@link simpledb.server.SimpleDB#initFileMgr(String)}
* is called first.
* @param logfile the name of the log file
*/
public LogMgr(String logfile) {
this.logfile = logfile;
int logsize = SimpleDB.fileMgr().size(logfile);
if (logsize == 0)
appendNewBlock();
else {
currentblk = new Block(logfile, logsize-1);
mypage.read(currentblk);
currentpos = getLastRecordPosition() + INT_SIZE;
}
}
/**
* Ensures that the log records corresponding to the
* specified LSN has been written to disk.
* All earlier log records will also be written to disk.
* @param lsn the LSN of a log record
*/
public void flush(int lsn) {
if (lsn >= currentLSN()) {
flush();
}
}
/**
* Returns an iterator for the log records,
* which will be returned in reverse order starting with the most recent.
* @see java.lang.Iterable#iterator()
*/
public synchronized Iterator<BasicLogRecord> iterator() {
flush();
return new LogIterator(currentblk);
}
/**
* Appends a log record to the file.
* The record contains an arbitrary array of strings and integers.
* The method also writes an integer to the end of each log record whose value
* is the offset of the corresponding integer for the previous log record.
* These integers allow log records to be read in reverse order.
* @param rec the list of values
* @return the LSN of the final value
*/
public synchronized int append(Object[] rec) {
int recsize = INT_SIZE; // 4 bytes for the integer that points to the previous log record
for (Object obj : rec)
recsize += size(obj);
if (currentpos + recsize >= BLOCK_SIZE){ // the log record doesn't fit,
flush(); // so move to the next block.
appendNewBlock();
}
for (Object obj : rec)
appendVal(obj);
finalizeRecord();
//int lsn = currentLSN() + (++increment);
int lsn = currentLSN() ;
return lsn;
}
/**
* Adds the specified value to the page at the position denoted by
* currentpos. Then increments currentpos by the size of the value.
* @param val the integer or string to be added to the page
*/
private void appendVal(Object val) {
if (val instanceof String) {
mypage.setString(currentpos, (String)val);
wasModified = true;
}
else {
mypage.setInt(currentpos, (Integer)val);
wasModified = true;
}
currentpos += size(val);
}
/**
* Calculates the size of the specified integer or string.
* @param val the value
* @return the size of the value, in bytes
*/
private int size(Object val) {
if (val instanceof String) {
String sval = (String) val;
return STR_SIZE(sval.length());
}
else
return INT_SIZE;
}
/**
* Returns the LSN of the most recent log record.
* As implemented, the LSN is the block number where the record is stored.
* Thus every log record in a block has the same LSN.
* @return the LSN of the most recent log record
*/
private int currentLSN() {
return currentblk.number();
}
/**
* Writes the current page to the log file.
*/
private void flush() {
if(wasModified) {
mypage.write(currentblk);
wasModified = false;
}
}
/**
* Clear the current page, and append it to the log file.
*/
private void appendNewBlock() {
wasModified = true;
setLastRecordPosition(0);
currentpos = INT_SIZE;
currentblk = mypage.append(logfile);
}
/**
* Sets up a circular chain of pointers to the records in the page.
* There is an integer added to the end of each log record
* whose value is the offset of the previous log record.
* The first four bytes of the page contain an integer whose value
* is the offset of the integer for the last log record in the page.
*/
private void finalizeRecord() {
mypage.setInt(currentpos, getLastRecordPosition());
setLastRecordPosition(currentpos);
currentpos += INT_SIZE;
}
private int getLastRecordPosition() {
return mypage.getInt(LAST_POS);
}
private void setLastRecordPosition(int pos) {
mypage.setInt(LAST_POS, pos);
}
}
public类LogMgr实现Iterable{
/**
*指向页面中最后一个整数的指针所在的位置。
*值为0表示指针是页面中的第一个值。
*/
公共静态最终整数最后位置=0;
私有字符串日志文件;
私有页面mypage=新页面();
私人大厦;
私人国际邮政局;
私有整数增量=0;
私有布尔值wasModified=false;
/**
*为指定的日志文件创建管理器。
*如果日志文件尚不存在,则会创建它
*第一个街区是空的。
*此构造函数依赖于{@link FileMgr}对象
*它从方法中得到的
*{@link simpledb.server.simpledb#fileMgr()}。
*该对象是在系统初始化期间创建的。
*因此,直到
*{@link simpledb.server.simpledb#initFileMgr(字符串)}
*第一个被称为。
*@param logfile日志文件的名称
*/
公共日志管理器(字符串日志文件){
this.logfile=logfile;
int logsize=SimpleDB.fileMgr().size(日志文件);
如果(logsize==0)
appendNewBlock();
否则{
currentblk=新块(日志文件,日志大小-1);
mypage.read(当前BLK);
currentpos=getLastRecordPosition()+整数大小;
}
}
/**
*确保日志记录与
*指定的LSN已写入磁盘。
*所有以前的日志记录也将写入磁盘。
*@param lsn日志记录的lsn
*/
公共无效刷新(内部lsn){
如果(lsn>=currentLSN()){
冲洗();
}
}
/**
*返回日志记录的迭代器,
*将从最新的开始以相反的顺序返回。
*@see java.lang.Iterable#iterator()
*/
公共同步迭代器迭代器(){
冲洗();
返回新的登录器(currentblk);
}
/**
*将日志记录追加到文件。
*该记录包含字符串和整数的任意数组。
*该方法还将一个整数写入其值为
*是上一个日志记录对应整数的偏移量。
*这些整数允许以相反的顺序读取日志记录。
*@param rec值列表
*@返回最终值的LSN
*/
公共同步int-append(对象[]rec){
int recsize=int_SIZE;//指向上一个日志记录的整数为4字节
用于(对象对象对象:rec)
recsize+=尺寸(obj);
如果(currentpos+recsize>=块大小){//日志记录不适合,
flush();//因此移动到下一个块。
appendNewBlock();
}
用于(对象对象对象:rec)
阑尾;
终结记录();
//int lsn=currentLSN()+(++增量);
int lsn=currentLSN();
返回lsn;
}
/**
*将指定的值添加到页面的以下位置
*currentpos。然后按值的大小递增currentpos。
*@param val要添加到页面的整数或字符串
*/
私有无效附件(对象val){
if(字符串的val instanceof){
mypage.setString(currentpos,(String)val);
wasModified=true;
}
否则{
mypage.setInt(currentpos,(整数)val);
wasModified=true;
}
currentpos+=大小(val);
}
/**
*计算指定整数或字符串的大小。
*@param val值
*@返回值的大小,以字节为单位
*/
私有整数大小(对象值){
if(字符串的val instanceof){
字符串sval=(字符串)val;
返回stru大小(sval.length());
}
其他的
返回整数大小;
}
/**
*返回最近日志记录的LSN。
*在实现时,LSN是存储记录的块号。
*因此,块中的每个日志记录都具有相同的LSN。
*@返回最近日志记录的LSN
*/
private int currentLSN(){
返回currentblk.number();
}
/**
*将当前页写入日志文件。
*/
私有空间刷新(){
如果(已修改){
mypage.write(当前BLK);
wasModified=false;
}
}
/**
*清除当前页面,并将其附加到日志文件中。
*/
私有void appendNewBlock(){
wasModified=true;
setLastRecordPosition(0);
currentpos=整数大小;
currentblk=mypage.append(日志文件);
}
/**
*设置指向页面中记录的循环指针链。
*每个日志记录的末尾都添加了一个整数
*其值是上一个日志记录的偏移量。
*页面的前四个字节包含一个值为
*是页面中最后一条日志记录的整数偏移量。
*/
私有void finalizeRecord(){
setInt(currentpos,getLastRecordPosition());
setLastRecordPosition(当前位置);
currentpos+=内部大小;
}
私有int getLastRecordPosition(){
返回mypage.getInt(最后一个位置);
}
私有无效setLastRe