initial commit with everything
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>edu.cs.purdue</groupId>
|
||||
<artifactId>cs448p2</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<name>cs448p2</name>
|
||||
<url>https://www.cs.purdue.edu/homes/bb/cs448f19/</url>
|
||||
|
||||
<properties>
|
||||
<java.version>10</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.mapdb/mapdb -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>minibase</groupId>
|
||||
<artifactId>bufmgr-project</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${basedir}/lib/bufmgrAssign.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
|
||||
<plugins>
|
||||
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<release>${java.version}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
</plugin>
|
||||
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
|
||||
<plugin>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>test.TestDriver</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,236 @@
|
||||
package bufmgr;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import diskmgr.DiskMgrException;
|
||||
import global.Minibase;
|
||||
import global.Page;
|
||||
import global.PageId;
|
||||
|
||||
/**
|
||||
* <h3>Minibase Buffer Manager</h3>
|
||||
* The buffer manager reads disk pages into a main memory page as needed. The
|
||||
* collection of main memory pages (called frames) used by the buffer manager
|
||||
* for this purpose is called the buffer pool. This is just an array of Page
|
||||
* objects. The buffer manager is used by access methods, heap files, and
|
||||
* relational operators to read, write, allocate, and de-allocate pages.
|
||||
*/
|
||||
public class BufMgr {
|
||||
|
||||
// INSTANCE VARIABLES
|
||||
// Some of these are accessed during the test cases
|
||||
// DO NOT CHANGE THE BELOW INSTANCE VARIABLE NAMES - you should use them as appropriate in your code
|
||||
// You may add additional ones as you need to
|
||||
|
||||
/** bufPool: the buffer pool. An array of Page objects */
|
||||
private Page[] bufPool = null;
|
||||
|
||||
/** frmDescr: An arracy of FrameDescriptor objects, holding information about the contents of each frame. */
|
||||
private FrameDescriptor[] frmDescr = null;
|
||||
|
||||
/** numOfFrames: the number of frames used for the maximum capacity of the buffer pool */
|
||||
private int numOfFrames = -1;
|
||||
|
||||
/** replacementPolicy: will be set to FIFO when the constructor is called. */
|
||||
private static String replacementPolicy = "FIFO";
|
||||
|
||||
/** map: Hash table to track which frame in the buffer a page is in <Key: PageID, Value: Frame> */
|
||||
private Map<Integer, Integer> pageMap = new HashMap<>();
|
||||
//
|
||||
|
||||
/** fifo: queue for FIFO page replacement. All unpinned pages will be stored here, with the first element being
|
||||
* the pageID that was unpinned the longest time ago */
|
||||
private Queue<Integer> fifo = new LinkedList<>();
|
||||
|
||||
// END OF REQUIRED INSTANCE VARIABLES
|
||||
|
||||
/**
|
||||
* Resets a FrameDescriptor to the default values with no pageID
|
||||
*/
|
||||
protected void resetFrameDescriptor(int frameId) {
|
||||
resetFrameDescriptor(frameId, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a FrameDescriptor to the default values with the given pageID
|
||||
*/
|
||||
protected void resetFrameDescriptor(int frameId, int pageno) {
|
||||
frmDescr[frameId].pageno = pageno;
|
||||
frmDescr[frameId].pinCount = 0;
|
||||
frmDescr[frameId].dirtyBit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the BufMgr object. Allocate pages (frames) for the buffer pool in main
|
||||
* memory and make the buffer manage aware that the replacement policy is
|
||||
* specified by replacerArg (e.g., LH, Clock, LRU, MRU, LIRS, etc.).
|
||||
*
|
||||
* @param numbufs
|
||||
* number of buffers in the buffer pool
|
||||
* @param lookAheadSize
|
||||
* number of pages to be looked ahead - can be ignored for this assignment
|
||||
* @param replacementPolicy
|
||||
* Name of the replacement policy
|
||||
*/
|
||||
public BufMgr(int numbufs, int lookAheadSize, String replacementPolicy) {
|
||||
// we ignore replacementPolicy as there is only one policy implemented in the
|
||||
// system
|
||||
numOfFrames = numbufs;
|
||||
bufPool = new Page[numOfFrames];
|
||||
frmDescr = new FrameDescriptor[numOfFrames];
|
||||
this.replacementPolicy = replacementPolicy;
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
bufPool[i] = new Page();
|
||||
frmDescr[i] = new FrameDescriptor();
|
||||
resetFrameDescriptor(i, -1);
|
||||
fifo.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin a page. First check if this page is already in the buffer pool. If it is,
|
||||
* increment the pin_count and return a pointer to this page. If the pin_count
|
||||
* was 0 before the call, the page was a replacement candidate, but is no longer
|
||||
* a candidate. If the page is not in the pool, choose a frame (from the set of
|
||||
* replacement candidates) to hold this page, read the page (using the
|
||||
* appropriate method from diskmgr package) and pin it. Also, must write out the
|
||||
* old page in chosen frame if it is dirty before reading new page.(You can
|
||||
* assume that emptyPage==false for this assignment.)
|
||||
*
|
||||
* @param pageno
|
||||
* page number in the Minibase.
|
||||
* @param page
|
||||
* the pointer point to the page.
|
||||
* @throws BufferPoolExceededException if there are no valid replacement candidates when attempting to pin a page not already in memory
|
||||
* @throws DiskMgrException if there is an error from the DiskMgr layer. This is likely caused by incorrect implementations of other methods in the BufferManager
|
||||
*/
|
||||
public void pinPage(PageId pageno, Page page, boolean emptyPage)
|
||||
throws BufferPoolExceededException, DiskMgrException {
|
||||
// YOUR CODE HERE
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin a page specified by a pageId. This method should be called with
|
||||
* dirty==true if the client has modified the page. If so, this call should set
|
||||
* the dirty bit for this frame. Further, if pin_count>0, this method should
|
||||
* decrement it. If pin_count=0 before this call, throw an exception to report
|
||||
* error. (For testing purposes, we ask you to throw an exception named
|
||||
* PageUnpinnedException in case of error.)
|
||||
*
|
||||
* @param pageno
|
||||
* the PageID of the page
|
||||
* @param dirty
|
||||
* whether or not the page is dirty
|
||||
* @throws PageNotFoundException the page is not in memory
|
||||
* @throws PageUnpinnedException the page is already unpinned
|
||||
*/
|
||||
public void unpinPage(PageId pageno, boolean dirty)
|
||||
throws PageNotFoundException, PageUnpinnedException {
|
||||
// YOUR CODE HERE
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate new pages. Call DB object to allocate a run of new pages and find a
|
||||
* frame in the buffer pool for the first page and pin it. (This call allows a
|
||||
* client of the Buffer Manager to allocate pages on disk.) If buffer is full,
|
||||
* i.e., you can't find a frame for the first page, ask DB to deallocate all
|
||||
* these pages, and return null.
|
||||
*
|
||||
* @param firstpage
|
||||
* the address of the first page.
|
||||
* @param howmany
|
||||
* total number of allocated new pages.
|
||||
*
|
||||
* @return the first page id of the new pages.__ null, if error.
|
||||
* @throws DiskMgrException if there is an error from the DiskMgr layer. This is likely caused by incorrect implementations of other methods of the Buffer Manager
|
||||
* @throws BufferPoolExceededException if the new page cannot be pinned after the run is allocated due to the buffer being full. If this exception is thrown, the newly allocated pages should be deallocated
|
||||
*/
|
||||
public PageId newPage(Page firstpage, int howmany) throws DiskMgrException, BufferPoolExceededException {
|
||||
// YOUR CODE HERE
|
||||
return new PageId();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called to delete a page that is on disk. This routine
|
||||
* must call the method in diskmgr package to deallocate the page.
|
||||
*
|
||||
* @param pageno
|
||||
* the page number in the data base.
|
||||
* @throws PagePinnedException if the page is still pinned
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void freePage(PageId pageno) throws PagePinnedException, DiskMgrException {
|
||||
// YOUR CODE HERE
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to flush a particular page of the buffer pool to disk. This method calls
|
||||
* the write_page method of the diskmgr package.
|
||||
*
|
||||
* @param pageid
|
||||
* the page number in the database.
|
||||
* @throws PageNotFoundException if the page is not in memory
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void flushPage(PageId pageid) throws PageNotFoundException, DiskMgrException {
|
||||
// find the frame holding that page
|
||||
Integer frameId = pageMap.get(pageid.pid);
|
||||
if (frameId == null) {
|
||||
throw new PageNotFoundException(
|
||||
"BufMgr.flushPage: Page with id " + pageid.pid + " does not exist in the buffer bool.");
|
||||
} else {
|
||||
Minibase.DiskManager.write_page(pageid, bufPool[frameId]);
|
||||
frmDescr[frameId].dirtyBit = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to flush all dirty pages in the buffer pool to disk
|
||||
* @throws DiskMgrException if there is an error in the DiskMgr layer. This is likely caused by incorrect implementations in other methods of the Buffer Manager
|
||||
*/
|
||||
public void flushAllPages() throws DiskMgrException {
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
if (frmDescr[i].dirtyBit == true) {
|
||||
Minibase.DiskManager.write_page(new PageId(frmDescr[i].pageno), bufPool[i]);
|
||||
frmDescr[i].dirtyBit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of buffer frames.
|
||||
*/
|
||||
public int getNumBuffers() {
|
||||
return numOfFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of unpinned buffer frames.
|
||||
*/
|
||||
public int getNumUnpinned() {
|
||||
int numUnpinned = 0;
|
||||
for (int i = 0; i < numOfFrames; i++) {
|
||||
if (frmDescr[i].pinCount <= 0) {
|
||||
numUnpinned++;
|
||||
}
|
||||
}
|
||||
return numUnpinned;
|
||||
}
|
||||
|
||||
//*** DO NOT CHANGE ANY EXISTING METHODS BELOW THIS LINE ***
|
||||
// Accessor methods for use in test cases
|
||||
public FrameDescriptor getFrameDesc(int frameNum) {
|
||||
return frmDescr[frameNum];
|
||||
}
|
||||
|
||||
public Page getPageFromFrame(int frameNum) {
|
||||
return bufPool[frameNum];
|
||||
}
|
||||
|
||||
public Integer getFrameFromPage(PageId pid) {
|
||||
return pageMap.get(new Integer(pid.pid));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package bufmgr;
|
||||
|
||||
public class BufMgrException extends Throwable
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -53906392083428894L;
|
||||
|
||||
public BufMgrException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package bufmgr;
|
||||
|
||||
public class BufferPoolExceededException extends BufMgrException
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -3879729988119933114L;
|
||||
|
||||
public BufferPoolExceededException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
/**
|
||||
* A frame descriptor; contains info about each page in the buffer pool.
|
||||
*/
|
||||
public class FrameDescriptor
|
||||
{
|
||||
/** Identifies the frame's page. */
|
||||
public int pageno = -1;
|
||||
|
||||
/** The frame's pin count. */
|
||||
public int pinCount;
|
||||
|
||||
/** The frame's dirty status. */
|
||||
public boolean dirtyBit;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PageNotFoundException extends BufMgrException
|
||||
{
|
||||
|
||||
public PageNotFoundException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8527332129053870174L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PagePinnedException extends BufMgrException
|
||||
{
|
||||
|
||||
public PagePinnedException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 2891505249472036297L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package bufmgr;
|
||||
|
||||
public class PageUnpinnedException extends BufMgrException
|
||||
{
|
||||
|
||||
public PageUnpinnedException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8366005988643934461L;
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
package diskmgr;
|
||||
|
||||
public class DiskMgrException extends Exception {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -6796603846181216651L;
|
||||
|
||||
public DiskMgrException(String name)
|
||||
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package diskmgr;
|
||||
|
||||
public class DuplicateEntryException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -7360431299339776190L;
|
||||
|
||||
public DuplicateEntryException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileEntryNotFoundException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -5657953921202448803L;
|
||||
|
||||
public FileEntryNotFoundException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileIOException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6320388561056052984L;
|
||||
|
||||
public FileIOException(String msg)
|
||||
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package diskmgr;
|
||||
|
||||
public class FileNameTooLongException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -4115614718485246811L;
|
||||
|
||||
public FileNameTooLongException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package diskmgr;
|
||||
|
||||
public class InvalidPageNumberException extends DiskMgrException {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 5106265663568991693L;
|
||||
|
||||
public InvalidPageNumberException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package diskmgr;
|
||||
|
||||
public class InvalidRunSizeException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1663588077268780074L;
|
||||
|
||||
public InvalidRunSizeException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package diskmgr;
|
||||
|
||||
public class OutOfSpaceException extends DiskMgrException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 2560165916249758898L;
|
||||
|
||||
public OutOfSpaceException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,952 @@
|
||||
package tests;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import bufmgr.*;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
|
||||
import diskmgr.DiskMgrException;
|
||||
import diskmgr.OutOfSpaceException;
|
||||
import global.Convert;
|
||||
import global.GlobalConst;
|
||||
import global.Minibase;
|
||||
import global.Page;
|
||||
import global.PageId;
|
||||
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
public class BMTest implements GlobalConst {
|
||||
|
||||
public final static boolean OK = true;
|
||||
public final static boolean FAIL = false;
|
||||
|
||||
/** Default database size (in pages). */
|
||||
private final static int DB_SIZE = 10000;
|
||||
|
||||
/** Default buffer pool size (in pages) */
|
||||
private final static int BUF_SIZE = 100;
|
||||
|
||||
/** Default number of pages to be looked ahead */
|
||||
private final static int LAH_SIZE = 10;
|
||||
|
||||
// Filepaths
|
||||
private static String dbpath;
|
||||
private static String logpath;
|
||||
private static final String REMOVE_CMD = "/bin/rm -rf ";
|
||||
private static String remove_logcmd;
|
||||
private static String remove_dbcmd;
|
||||
|
||||
// Instance variables for tests
|
||||
private static int numPages;
|
||||
|
||||
private static Page pg;
|
||||
private static PageId pid, first_pid, last_pid;
|
||||
|
||||
private void checkFDContents(FrameDescriptor fd, int pgid, int pinCount, boolean dirty) {
|
||||
String failmsg = "Failed: - ";
|
||||
boolean passed = true;
|
||||
if (fd.pageno != pgid) {
|
||||
failmsg += "FD pagenumber: " + fd.pageno + ", should be " + pgid + " - ";
|
||||
passed = false;
|
||||
}
|
||||
if (fd.pinCount != pinCount) {
|
||||
failmsg += "FD pincount: " + fd.pinCount + ", should be " + pinCount + " - ";
|
||||
passed = false;
|
||||
}
|
||||
if (fd.dirtyBit != dirty) {
|
||||
failmsg += "Fd dirty bit: " + fd.dirtyBit + ", should be " + dirty;
|
||||
passed = false;
|
||||
}
|
||||
assertTrue(failmsg, passed);
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpBeforeClass() throws Exception {
|
||||
|
||||
// Set up remove commands and ensure nothing's left over
|
||||
String remove_cmd = "/bin/rm -rf ";
|
||||
|
||||
dbpath = "/tmp/" + System.getProperty("user.name") + ".minibase-db";
|
||||
logpath = "/tmp/" + System.getProperty("user.name") + ".minibase-log";
|
||||
|
||||
remove_logcmd = REMOVE_CMD + logpath;
|
||||
remove_dbcmd = REMOVE_CMD + dbpath;
|
||||
|
||||
// Commands here is very machine dependent. We assume
|
||||
// user are on UNIX system here
|
||||
try {
|
||||
Runtime.getRuntime().exec(remove_logcmd);
|
||||
Runtime.getRuntime().exec(remove_dbcmd);
|
||||
} catch (IOException e) {
|
||||
System.err.println("" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
new Minibase(dbpath, DB_SIZE, BUF_SIZE, LAH_SIZE, "FIFO", false);
|
||||
|
||||
numPages = Minibase.BufferManager.getNumUnpinned();
|
||||
pg = new Page();
|
||||
pid = new PageId();
|
||||
first_pid = new PageId();
|
||||
last_pid = new PageId();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
// Remove anything from previous tests
|
||||
// Commands here are very machine dependent. We assume
|
||||
// user are on UNIX system here
|
||||
try {
|
||||
Runtime.getRuntime().exec(remove_logcmd);
|
||||
Runtime.getRuntime().exec(remove_dbcmd);
|
||||
} catch (IOException e) {
|
||||
System.err.println("" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testA_PinPageNotInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page - check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testB_PinPinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for repinning already pinned page", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr pinning pinned page", false);
|
||||
}
|
||||
// Allocated and pinned one page twice - check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 2, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testC_UnpinPinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it - check that it's in hash
|
||||
// table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after unpinning", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after unpinning", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 0, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testD_PinUnpinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException bpe_ex) {
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full when attempting to repin unpinned page in buffer", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr repinning page", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it, then pinned it again
|
||||
// check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after repinning page", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after repinning page", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testE_UnpinUnpinnedPageInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Unpin the page twice so that we will be unpinning an unpinned page
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning unpinned page", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
assertTrue(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here, the expected exception was not returned
|
||||
assertTrue("Failed: PageUnpinnedException not properly thrown", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testF_UnpinDirtyPage() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated and pinned one page, then unpinned it as dirty
|
||||
// check that it's in hash table
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table after unpinning", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame after unpinning", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, first_pid.pid, 0, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testG_UnpinPageNotInMemory() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 2);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table while unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Allocated two pages and pinned/unpinned first one
|
||||
// Now attempt to unpin second, never-pinned page
|
||||
pid = new PageId(first_pid.pid + 1);
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
assertTrue(true);
|
||||
return;
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue(
|
||||
"Unexpected Failure: PageUnpinnedException thrown, but should have returned HashNotFoundException",
|
||||
false);
|
||||
}
|
||||
|
||||
// If we get here, the expected exception was not returned
|
||||
assertTrue("Failed: PageNotFoundException not properly thrown", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testH_PinPageNotInMemoryWithReplacement() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin and unpin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for pinning page " + pid.pid, false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(last_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid, false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager when performing replacement", false);
|
||||
}
|
||||
|
||||
// Pinned a page using replacement policy - verify that FD is correct
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(last_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page not in hash table", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page not in frame", false);
|
||||
FrameDescriptor fd = Minibase.BufferManager.getFrameDesc(fnum);
|
||||
checkFDContents(fd, last_pid.pid, 1, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testI_PinPageReplaceDirtyPage() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin and unpin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: could not write page data for page " + pid.pid, false);
|
||||
}
|
||||
// Unpin page - it's dirty
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory, then unpin it
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid + 1
|
||||
+ " during replacement", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager when performing replacement", false);
|
||||
}
|
||||
// Pinned a page using replacement policy - FIFO should remove page with
|
||||
// pid=first_pid
|
||||
// Verify that page data in frame is overwritten
|
||||
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
if (data == first_pid.pid + 99999)
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + pid.pid, false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
// Bring in page with pid=first_pid again and see if its data is retrieved
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded bringing first page in from memory " + first_pid.pid
|
||||
+ " during replacement", false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager bringing first page in from memory", false);
|
||||
}
|
||||
// Verify contents of page after bringing back from disk
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(first_pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + first_pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + first_pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
// Finally, check page
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", data == first_pid.pid + 99999);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + first_pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJ_FIFOBehavior() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write data for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Pick three pages to unpin. Store the frames for reference later
|
||||
PageId pg1 = new PageId(), pg2 = new PageId(), pg3 = new PageId();
|
||||
int pageRange = last_pid.pid - first_pid.pid;
|
||||
pg1.pid = first_pid.pid + (pageRange / 3);
|
||||
Integer f1 = Minibase.BufferManager.getFrameFromPage(pg1);
|
||||
pg2.pid = first_pid.pid + (pageRange / 3) * 2;
|
||||
Integer f2 = Minibase.BufferManager.getFrameFromPage(pg2);
|
||||
pg3.pid = first_pid.pid + pageRange-1;
|
||||
Integer f3 = Minibase.BufferManager.getFrameFromPage(pg3);
|
||||
|
||||
// Unpin pages in order: pg2, pg1, pg3. FIFO should then select pg3 to evict
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg2, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg1, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg3, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg3.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg3.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for last page " + last_pid.pid + 1
|
||||
+ " during replacement", false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager during replacement", false);
|
||||
}
|
||||
// Pinned a page using replacement policy - FIFO should remove page with pid=pg2
|
||||
// Verify that page data in frame is overwritten
|
||||
|
||||
try {
|
||||
Integer fnum = Minibase.BufferManager.getFrameFromPage(pid);
|
||||
if (fnum == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in hash table after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
if (pg == null)
|
||||
assertTrue("Failed: page " + pid.pid + " not in frame after replacement", false);
|
||||
pg = Minibase.BufferManager.getPageFromFrame(fnum);
|
||||
int data = Convert.getIntValue(0, pg.getpage());
|
||||
if (data == pg2.pid + 99999)
|
||||
assertTrue("Failure: page stored in frame not overwritten when replaced", false);
|
||||
// Now that replacement policy has been used, verify we actually evicted pg3
|
||||
assertTrue("Failed: wrong page evicted, should be page " + pg2.pid + " in frame " + f2, fnum == f2);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: reading from page " + pid.pid, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testK_BufferFull() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write to page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Now attempt to bring another page into memory, it should fail
|
||||
pid.pid = last_pid.pid + 1;
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException bpe_ex) {
|
||||
assertTrue(true);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
}
|
||||
|
||||
// If we reach here, expected exception was not thrown
|
||||
assertTrue("Failure: expected BufferPoolExceeded exception not thrown thrown for page " + pid.pid, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testL_NewPageDeallocation()
|
||||
{
|
||||
//Allocate enough pages to fill the buffer
|
||||
int numTestPages = numPages - 3; //-3 here is to account for required DiskMgr pages, which we will force to be pinned for this test
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numTestPages);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
//Force all required DiskMgr pages to be pinned
|
||||
for(pid.pid = 0; pid.pid < first_pid.pid; pid.pid = pid.pid + 1)
|
||||
{
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for DiskMgr page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for DiskMgr page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid+1, last_pid.pid = first_pid.pid + numTestPages; pid.pid < last_pid.pid; pid.pid = pid.pid
|
||||
+ 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
//Allocate enough pages to completely fill the database. However, we expect pinning the page to fail here
|
||||
boolean pin = true;
|
||||
try {
|
||||
pid = Minibase.BufferManager.newPage(pg, DB_SIZE - last_pid.pid);
|
||||
} catch (DiskMgrException e) {
|
||||
e.printStackTrace();
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for allocation that fills the DB", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
//Set a flag to show this exception was thrown successfully
|
||||
pin = false;
|
||||
}
|
||||
if(pin)
|
||||
assertTrue("Unexpected Failure: Page allocation with full buffer did not throw BufferPoolExceededException", false);
|
||||
|
||||
//Unpin all pages
|
||||
for (pid.pid = 0; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page " + pid.pid + " already unpinned", false);
|
||||
}
|
||||
}
|
||||
|
||||
//Allocate new pages again - this should succeed now that the buffer is unpinned
|
||||
try {
|
||||
pid = Minibase.BufferManager.newPage(pg, DB_SIZE - last_pid.pid);
|
||||
} catch (OutOfSpaceException e) {
|
||||
assertTrue("Failure: disk pages not deallocated after failure to pin them", false);
|
||||
} catch (DiskMgrException e) {
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for allocation that fills the DB", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
assertTrue("Unexpected Failure: buffer pool full when trying to allocate new pages", false);
|
||||
}
|
||||
|
||||
//If we get here, then we have succeeded
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@Test //This is a simple test to demonstrate Freepage method. We create a new empty page, bring it to memory queue but do NOT pin it. It should be able to safely free the page.
|
||||
public void testM_FreeAnEmptyPage()
|
||||
{
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(first_pid);
|
||||
//assertTrue("freepage success", true);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Failed: Page pinned already", true);
|
||||
//System.out.println(" --> Failed as expected \n");
|
||||
//status = FAIL; // what we want
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Test //This test first creates a new emopty page, pins it and tries to Free it but as it is pinned already, we expect it to fail.
|
||||
public void testN_FreeAPinnedPage(){
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(first_pid, pg, false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for repinning already pinned page", false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr pinning pinned page", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(first_pid);
|
||||
assertTrue("Unexpected behavior: Freepage was a success even though page was pinned", false);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Success i.e. Failed as expected: Page pinned already - so Freepage will not suceed. This is the expected behavior.", true);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testO_FreePageOnWrittenPages() {
|
||||
try {
|
||||
first_pid = Minibase.BufferManager.newPage(pg, numPages + 1);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: error with DiskMgr for initial allocation", false);
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: Buffer Pool Full for initial allocation", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(first_pid, false);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page not found in hash table when unpinning", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: page already unpinned", false);
|
||||
}
|
||||
// Pin enough pages to fill buffer
|
||||
for (pid.pid = first_pid.pid, last_pid.pid = pid.pid + numPages; pid.pid < last_pid.pid; pid.pid = pid.pid + 1) {
|
||||
try {
|
||||
Minibase.BufferManager.pinPage(pid, pg, false);
|
||||
// Write some data to each page
|
||||
int data = pid.pid + 99999;
|
||||
Convert.setIntValue(data, 0, pg.getpage());
|
||||
} catch (BufferPoolExceededException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: BufferPoolExceeded exception thrown for page " + pid.pid, false);
|
||||
} catch (DiskMgrException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: exception at disk manager for page " + pid.pid, false);
|
||||
} catch (IOException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: cannot write data for page " + pid.pid, false);
|
||||
}
|
||||
}
|
||||
// Pick three pages to unpin. But unpin only two and keep the third pinned
|
||||
PageId pg1 = new PageId(), pg2 = new PageId(), pg3 = new PageId();
|
||||
int pageRange = last_pid.pid - first_pid.pid;
|
||||
pg1.pid = first_pid.pid + (pageRange / 3);
|
||||
Integer f1 = Minibase.BufferManager.getFrameFromPage(pg1);
|
||||
pg2.pid = first_pid.pid + (pageRange / 3) * 2;
|
||||
Integer f2 = Minibase.BufferManager.getFrameFromPage(pg2);
|
||||
pg3.pid = first_pid.pid + pageRange-1;
|
||||
Integer f3 = Minibase.BufferManager.getFrameFromPage(pg3);
|
||||
// Unpin pages in order: pg2, pg1, pg3 (as should be in FIFO policy). But for the test we do not unpin pg3
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg2, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg2.pid + " already unpinned", false);
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.unpinPage(pg1, true);
|
||||
} catch (PageNotFoundException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " not found in hash table", false);
|
||||
} catch (PageUnpinnedException e) {
|
||||
|
||||
assertTrue("Unexpected Failure: replacement page " + pg1.pid + " already unpinned", false);
|
||||
}
|
||||
|
||||
try {
|
||||
Minibase.BufferManager.freePage(pg1);
|
||||
assertTrue("Tests passed: PG1 was unpinned and should be able to be freed", true);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test Failed i.e. should be able to free an empty page", false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
Minibase.BufferManager.freePage(pg3);
|
||||
assertTrue("Tests failed: PG3 was pinned (and written) and should NOT be able to be freed", false);
|
||||
} catch (PagePinnedException e) {
|
||||
assertTrue("Test passed i.e. should not be able to free a pinned page that was written on", true);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package tests;
|
||||
|
||||
import org.junit.runner.JUnitCore;
|
||||
import org.junit.runner.Result;
|
||||
import org.junit.runner.notification.Failure;
|
||||
|
||||
public class TestDriver {
|
||||
public static void main(String[] args) {
|
||||
Result result = JUnitCore.runClasses(tests.BMTest.class);
|
||||
|
||||
for (Failure failure : result.getFailures()) {
|
||||
System.out.println(failure.toString());
|
||||
}
|
||||
|
||||
System.out.println(result.wasSuccessful());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user