// see DbFile.java for javadocs public Page readPage(PageId pid) { int offset = BufferPool.PAGE_SIZE * pid.pageNumber(); byte[] b = new byte[BufferPool.PAGE_SIZE]; try { InputStream is = new FileInputStream(m_file); is.skip(offset); is.read(b, 0, BufferPool.PAGE_SIZE); is.close(); return new HeapPage((HeapPageId) pid, b); } catch (IOException ioe) { ioe.printStackTrace(); return null; } }
/** * Compares one PageId to another. * * @param o The object to compare against (must be a PageId) * @return true if the objects are equal (e.g., page numbers and table ids are the same) */ public boolean equals(Object o) { if (!(o instanceof PageId)) return false; PageId other = (PageId) o; if (this.getTableId() != other.getTableId() || this.pageNumber() != other.pageNumber()) return false; return true; }
/** * You should implement the hashCode() so that two equal RecordId instances (with respect to * equals()) have the same hashCode(). * * @return An int that is the same for equal RecordId objects. */ @Override public int hashCode() { // some code goes here return Integer.parseInt(pid.hashCode() + Integer.toString(tupleno)); // throw new UnsupportedOperationException("implement this"); }
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((pid == null) ? 0 : pid.hashCode()); result = prime * result + tupleno; return result; }
/** * Two RecordId objects are considered equal if they represent the same tuple. * * @return True if this and o represent the same tuple */ @Override public boolean equals(Object o) { // some code goes here if (o instanceof RecordId) { RecordId tmp = (RecordId) o; return pid.equals(tmp.getPageId()) && tmp.tupleno == tupleno; } return false; // throw new UnsupportedOperationException("implement this"); }
// see DbFile.java for javadocs public Page readPage(PageId pid) { // some code goes here if (pid.pageNumber() >= numPages()) { throw new IllegalArgumentException("page not in file"); } Page returnme = null; byte[] data = HeapPage.createEmptyPageData(); long offset = (long) BufferPool.PAGE_SIZE * pid.pageNumber(); try { raf.seek(offset); for (int i = 0; i < data.length; i++) { data[i] = raf.readByte(); } returnme = new HeapPage((HeapPageId) pid, data); } catch (EOFException eofe) { eofe.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } return returnme; }
/** * Retrieve the specified page with the associated permissions. Will acquire a lock and may block * if that lock is held by another transaction. * * <p>The retrieved page should be looked up in the buffer pool. If it is present, it should be * returned. If it is not present, it should be added to the buffer pool and returned. If there is * insufficient space in the buffer pool, an page should be evicted and the new page should be * added in its place. * * @param tid the ID of the transaction requesting the page * @param pid the ID of the requested page * @param perm the requested permissions on the page * @throws IOException * @throws NoSuchElementException */ public Page getPage(TransactionId tid, PageId pid, Permissions perm) throws TransactionAbortedException, DbException, NoSuchElementException, IOException { if (this.deadPool.containsKey(pid)) { return this.deadPool.get(pid); } else { if (this.deadPool.size() >= this.numPages) { throw new DbException("Too many pages!"); } else { this.deadPool.put( pid, Database.getCatalog().getDatabaseFile(pid.getTableId()).readPage(pid)); return this.deadPool.get(pid); } } }
/** * Flushes a certain page to disk * * @param pageId an ID indicating the page to flush */ private synchronized void flushPage(PageId pageId) throws IOException { if (pageIdToPages.containsKey(pageId)) { Page page = pageIdToPages.get(pageId); // append an update record to the log, with // a before-image and after-image. TransactionId dirtier = page.isDirty(); if (dirtier != null) { addDirtiedFlushedPage(dirtier, pageId); Database.getLogFile().logWrite(dirtier, page.getBeforeImage(), page); Database.getLogFile().force(); Database.getCatalog().getDatabaseFile(pageId.getTableId()).writePage(page); page.markDirty(false, null); } } }
// see DbFile.java for javadocs public Page readPage(PageId pid) { // some code goes here try { RandomAccessFile rAf = new RandomAccessFile(f, "r"); int offset = pid.pageNumber() * BufferPool.PAGE_SIZE; byte[] b = new byte[BufferPool.PAGE_SIZE]; rAf.seek(offset); rAf.read(b, 0, BufferPool.PAGE_SIZE); HeapPageId hpid = (HeapPageId) pid; rAf.close(); return new HeapPage(hpid, b); } catch (IOException e) { e.printStackTrace(); } return null; }
/** * Retrieve the specified page with the associated permissions. Will acquire a lock and may block * if that lock is held by another transaction. * * <p>The retrieved page should be looked up in the buffer pool. If it is present, it should be * returned. If it is not present, it should be added to the buffer pool and returned. If there is * insufficient space in the buffer pool, an page should be evicted and the new page should be * added in its place. * * @param tid the ID of the transaction requesting the page * @param pid the ID of the requested page * @param perm the requested permissions on the page * @throws DbException * @throws TransactionAbortedException */ public Page getPage(TransactionId tid, PageId pid, Permissions perm) throws DbException, TransactionAbortedException { lockManager.acquireLock(tid, pid, perm); if (pageIdToPages.containsKey(pid)) { return pageIdToPages.get(pid); } if (currentPages.get() == maxPages) { evictPage(); } int tableId = pid.getTableId(); Catalog catalog = Database.getCatalog(); DbFile dbFile = catalog.getDatabaseFile(tableId); Page page = dbFile.readPage(pid); pageIdToPages.put(pid, page); currentPages.incrementAndGet(); return page; }
@Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof RecordId)) { return false; } RecordId other = (RecordId) obj; if (pid == null) { if (other.pid != null) { return false; } } else if (!pid.equals(other.pid)) { return false; } if (tupleno != other.tupleno) { return false; } return true; }
/** * overrides the test2 function in TestDriver. It tests whether illeagal operation can be caught. * * @return whether test2 has passed */ protected boolean test2() { System.out.print("\n Test 2 exercises some illegal buffer " + "manager operations:\n"); // We choose this number to ensure that pinning this number of buffers // should fail. int numPages = SystemDefs.JavabaseBM.getNumUnpinnedBuffers() + 1; Page pg = new Page(); PageId pid, lastPid; PageId firstPid = new PageId(); boolean status = OK; System.out.print(" - Try to pin more pages than there are frames\n"); try { firstPid = SystemDefs.JavabaseBM.newPage(pg, numPages); } catch (Exception e) { System.err.print("*** Could not allocate " + numPages); System.err.print(" new pages in the database.\n"); e.printStackTrace(); return false; } pid = new PageId(); lastPid = new PageId(); // First pin enough pages that there is no more room. for (pid.pid = firstPid.pid + 1, lastPid.pid = firstPid.pid + numPages - 1; status == OK && pid.pid < lastPid.pid; pid.pid = pid.pid + 1) { try { SystemDefs.JavabaseBM.pinPage(pid, pg, /*emptyPage:*/ true); } catch (Exception e) { status = FAIL; System.err.print("*** Could not pin new page " + pid.pid + "\n"); e.printStackTrace(); } } // Make sure the buffer manager thinks there's no more room. if (status == OK && SystemDefs.JavabaseBM.getNumUnpinnedBuffers() != 0) { status = FAIL; System.err.print( "*** The buffer manager thinks it has " + SystemDefs.JavabaseBM.getNumUnpinnedBuffers() + " available frames,\n" + " but it should have none.\n"); } // Now pin that last page, and make sure it fails. if (status == OK) { try { SystemDefs.JavabaseBM.pinPage(lastPid, pg, /*emptyPage:*/ true); } catch (ChainException e) { status = checkException(e, "bufmgr.BufferPoolExceededException"); if (status == FAIL) { System.err.print("*** Pinning too many pages\n"); System.out.println(" --> Failed as expected \n"); } } catch (Exception e) { e.printStackTrace(); } if (status == OK) { status = FAIL; System.err.print("The expected exception was not thrown\n"); } else { status = OK; } } if (status == OK) { try { SystemDefs.JavabaseBM.pinPage(firstPid, pg, /*emptyPage:*/ true); } catch (Exception e) { status = FAIL; System.err.print("*** Could not acquire a second pin on a page\n"); e.printStackTrace(); } if (status == OK) { System.out.print(" - Try to free a doubly-pinned page\n"); try { SystemDefs.JavabaseBM.freePage(firstPid); } catch (ChainException e) { status = checkException(e, "bufmgr.PagePinnedException"); if (status == FAIL) { System.err.print("*** Freeing a pinned page\n"); System.out.println(" --> Failed as expected \n"); } } catch (Exception e) { e.printStackTrace(); } if (status == OK) { status = FAIL; System.err.print("The expected exception was not thrown\n"); } else { status = OK; } } if (status == OK) { try { SystemDefs.JavabaseBM.unpinPage(firstPid, false); } catch (Exception e) { status = FAIL; e.printStackTrace(); } } } if (status == OK) { System.out.print(" - Try to unpin a page not in the buffer pool\n"); try { SystemDefs.JavabaseBM.unpinPage(lastPid, false); } catch (ChainException e) { status = checkException(e, "bufmgr.HashEntryNotFoundException"); if (status == FAIL) { System.err.print("*** Unpinning a page not in the buffer pool\n"); System.out.println(" --> Failed as expected \n"); } } catch (Exception e) { e.printStackTrace(); } if (status == OK) { status = FAIL; System.err.print("The expected exception was not thrown\n"); } else { status = OK; } } for (pid.pid = firstPid.pid; pid.pid <= lastPid.pid; pid.pid = pid.pid + 1) { try { SystemDefs.JavabaseBM.freePage(pid); } catch (Exception e) { status = FAIL; System.err.print("*** Error freeing page " + pid.pid + "\n"); e.printStackTrace(); } } if (status == OK) System.out.print(" Test 2 completed successfully.\n"); return status; }
/** * overrides the test1 function in TestDriver. It tests some simple normal buffer manager * operations. * * @return whether test1 has passed */ protected boolean test1() { System.out.print("\n Test 1 does a simple test of normal buffer "); System.out.print("manager operations:\n"); // We choose this number to ensure that at least one page will have to be // written during this test. boolean status = OK; int numPages = SystemDefs.JavabaseBM.getNumUnpinnedBuffers() + 1; Page pg = new Page(); PageId pid; PageId lastPid; PageId firstPid = new PageId(); System.out.print(" - Allocate a bunch of new pages\n"); try { firstPid = SystemDefs.JavabaseBM.newPage(pg, numPages); } catch (Exception e) { System.err.print("*** Could not allocate " + numPages); System.err.print(" new pages in the database.\n"); e.printStackTrace(); return false; } // Unpin that first page... to simplify our loop. try { SystemDefs.JavabaseBM.unpinPage(firstPid, false /*not dirty*/); } catch (Exception e) { System.err.print("*** Could not unpin the first new page.\n"); e.printStackTrace(); status = FAIL; } System.out.print(" - Write something on each one\n"); pid = new PageId(); lastPid = new PageId(); for (pid.pid = firstPid.pid, lastPid.pid = pid.pid + numPages; status == OK && pid.pid < lastPid.pid; pid.pid = pid.pid + 1) { try { SystemDefs.JavabaseBM.pinPage(pid, pg, /*emptyPage:*/ true); } catch (Exception e) { status = FAIL; System.err.print("*** Could not pin new page " + pid.pid + "\n"); e.printStackTrace(); } if (status == OK) { // Copy the page number + 99999 onto each page. It seems // unlikely that this bit pattern would show up there by // coincidence. int data = pid.pid + 99999; try { Convert.setIntValue(data, 0, pg.getpage()); } catch (IOException e) { System.err.print("*** Convert value failed\n"); status = FAIL; } if (status == OK) { try { SystemDefs.JavabaseBM.unpinPage(pid, /*dirty:*/ true); } catch (Exception e) { status = FAIL; System.err.print("*** Could not unpin dirty page " + pid.pid + "\n"); e.printStackTrace(); } } } } if (status == OK) System.out.print( " - Read that something back from each one\n" + " (because we're buffering, this is where " + "most of the writes happen)\n"); for (pid.pid = firstPid.pid; status == OK && pid.pid < lastPid.pid; pid.pid = pid.pid + 1) { try { SystemDefs.JavabaseBM.pinPage(pid, pg, /*emptyPage:*/ false); } catch (Exception e) { status = FAIL; System.err.print("*** Could not pin page " + pid.pid + "\n"); e.printStackTrace(); } if (status == OK) { int data = 0; try { data = Convert.getIntValue(0, pg.getpage()); } catch (IOException e) { System.err.print("*** Convert value failed \n"); status = FAIL; } if (status == OK) { if (data != (pid.pid) + 99999) { status = FAIL; System.err.print("*** Read wrong data back from page " + pid.pid + "\n"); } } if (status == OK) { try { SystemDefs.JavabaseBM.unpinPage(pid, /*dirty:*/ true); } catch (Exception e) { status = FAIL; System.err.print("*** Could not unpin page " + pid.pid + "\n"); e.printStackTrace(); } } } } if (status == OK) System.out.print(" - Free the pages again\n"); for (pid.pid = firstPid.pid; pid.pid < lastPid.pid; pid.pid = pid.pid + 1) { try { SystemDefs.JavabaseBM.freePage(pid); } catch (Exception e) { status = FAIL; System.err.print("*** Error freeing page " + pid.pid + "\n"); e.printStackTrace(); } } if (status == OK) System.out.print(" Test 1 completed successfully.\n"); return status; }