📄 paged.java
字号:
page = null; } else { page = getPage(nextPage); } } // Add any overflow pages to the list of free pages. if (page != null) { // Get the first and last page in the chain. long firstPage = page.pageNum.longValue(); while (page.header.nextPage != NO_PAGE) { page = getPage(page.header.nextPage); } long lastPage = page.pageNum.longValue(); // Free the chain synchronized (fileHeader) { // If there are already some free pages, add the start of the chain // to the list of free pages. if (fileHeader.lastFreePage != NO_PAGE) { Page p = getPage(fileHeader.lastFreePage); p.header.setNextPage(firstPage); p.write(); } // Otherwise set the chain as the list of free pages. if (fileHeader.firstFreePage == NO_PAGE) { fileHeader.setFirstFreePage(firstPage); } // Add a reference to the end of the chain. fileHeader.setLastFreePage(lastPage); } } } /** * unlinkPages unlinks a set of pages starting at the specified * page number. * * @param pageNum The starting page number to unlink * @throws IOException if an Exception occurs */ protected final void unlinkPages(long pageNum) throws IOException { unlinkPages(getPage(pageNum)); } /** * getFreePage returns the first free Page from secondary storage. * If no Pages are available, the file is grown as appropriate. * * @return The next free Page * @throws IOException if an Exception occurs */ protected final Page getFreePage() throws IOException { Page p = null; // Synchronize read and write to the fileHeader.firstFreePage synchronized (fileHeader) { if (fileHeader.firstFreePage != NO_PAGE) { // Steal a deleted page p = getPage(fileHeader.firstFreePage); fileHeader.setFirstFreePage(p.getPageHeader().nextPage); if (fileHeader.firstFreePage == NO_PAGE) { fileHeader.setLastFreePage(NO_PAGE); } } } if (p == null) { // No deleted pages, grow the file p = getPage(fileHeader.incTotalCount()); } // Initialize The Page Header (Cleanly) p.header.setNextPage(NO_PAGE); p.header.setStatus(UNUSED); return p; } /** * @throws DBException COL_COLLECTION_CLOSED if paged file is closed */ protected final void checkOpened() throws DBException { if (!opened) { throw new FilerException(FaultCodes.COL_COLLECTION_CLOSED, "Filer is closed"); } } /** * getFileHeader returns the FileHeader * * @return The FileHeader */ public FileHeader getFileHeader() { return fileHeader; } public boolean exists() { return file.exists(); } public boolean create() throws DBException { RandomAccessFile raf = null; try { raf = getDescriptor(); fileHeader.write(); flush(); return true; } catch (Exception e) { throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error creating " + file.getName(), e); } } public boolean open() throws DBException { RandomAccessFile raf = null; try { if (exists()) { raf = getDescriptor(); fileHeader.read(); opened = true; } else { opened = false; } return opened; } catch (Exception e) { throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error opening " + file.getName(), e); } finally { putDescriptor(raf); } } public synchronized boolean close() throws DBException { if (isOpened()) { try { // First of all, mark as closed to prevent operations opened = false; flush(); synchronized (descriptors) { final int total = descriptorsCount; // Close descriptors in cache while (!descriptors.empty()) { closeDescriptor((RandomAccessFile)descriptors.pop()); } // Attempt to close descriptors in use. Max wait time = 0.5s * MAX_DESCRIPTORS int n = descriptorsCount; while (descriptorsCount > 0 && n > 0) { descriptors.wait(500); if (descriptors.isEmpty()) { n--; } else { closeDescriptor((RandomAccessFile)descriptors.pop()); } } if (descriptorsCount > 0) { LOG.warn(descriptorsCount + " out of " + total + " files were not closed during close."); } } } catch (Exception e) { // Failed to close, leave open opened = true; throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error closing " + file.getName(), e); } } return true; } public boolean isOpened() { return opened; } public boolean drop() throws DBException { try { close(); if (exists()) { return getFile().delete(); } else { return true; } } catch (Exception e) { throw new FilerException(FaultCodes.COL_CANNOT_DROP, "Can't drop " + file.getName(), e); } } void addDirty(Page page) throws IOException { synchronized (dirtyLock) { dirty.put(page.pageNum, page); if (dirty.size() > MAX_DIRTY_SIZE) { try { // Too many dirty pages... flush them flush(); } catch (Exception e) { throw new IOException(e.getMessage()); } } } } public void flush() throws DBException { // This method is not synchronized // Error flag/counter int error = 0; // Obtain collection of dirty pages Collection pages; synchronized (dirtyLock) { pages = dirty.values(); dirty = new HashMap(); } // Flush dirty pages Iterator i = pages.iterator(); while (i.hasNext()) { Page p = (Page) i.next(); try { p.flush(); } catch (Exception e) { LOG.warn("Exception while flushing page", e); error++; } } // Flush header if (fileHeader.dirty) { try { fileHeader.write(); } catch (Exception e) { LOG.warn("Exception while flushing file header", e); error++; } } if (error != 0) { throw new FilerException(FaultCodes.GEN_CRITICAL_ERROR, "Error performing flush! Failed to flush " + error + " pages!"); } } /** * createFileHeader must be implemented by a Paged implementation * in order to create an appropriate subclass instance of a FileHeader. * * @return a new FileHeader */ public abstract FileHeader createFileHeader(); /** * createFileHeader must be implemented by a Paged implementation * in order to create an appropriate subclass instance of a FileHeader. * * @param read If true, reads the FileHeader from disk * @return a new FileHeader * @throws IOException if an exception occurs */ public abstract FileHeader createFileHeader(boolean read) throws IOException; /** * createFileHeader must be implemented by a Paged implementation * in order to create an appropriate subclass instance of a FileHeader. * * @param pageCount The number of pages to allocate for primary storage * @return a new FileHeader */ public abstract FileHeader createFileHeader(long pageCount); /** * createFileHeader must be implemented by a Paged implementation * in order to create an appropriate subclass instance of a FileHeader. * * @param pageCount The number of pages to allocate for primary storage * @param pageSize The size of a Page (should be a multiple of a FS block) * @return a new FileHeader */ public abstract FileHeader createFileHeader(long pageCount, int pageSize); /** * createPageHeader must be implemented by a Paged implementation * in order to create an appropriate subclass instance of a PageHeader. * * @return a new PageHeader */ public abstract PageHeader createPageHeader(); // These are a bunch of utility methods for subclasses public static Value[] insertArrayValue(Value[] vals, Value val, int idx) { Value[] newVals = new Value[vals.length + 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } newVals[idx] = val; if (idx < vals.length) { System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); } return newVals; } public static Value[] deleteArrayValue(Value[] vals, int idx) { Value[] newVals = new Value[vals.length - 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } if (idx < newVals.length) { System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); } return newVals; } public static long[] insertArrayLong(long[] vals, long val, int idx) { long[] newVals = new long[vals.length + 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } newVals[idx] = val; if (idx < vals.length) { System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); } return newVals; } public static long[] deleteArrayLong(long[] vals, int idx) { long[] newVals = new long[vals.length - 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } if (idx < newVals.length) { System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); } return newVals; } public static int[] insertArrayInt(int[] vals, int val, int idx) { int[] newVals = new int[vals.length + 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } newVals[idx] = val; if (idx < vals.length) { System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); } return newVals; } public static int[] deleteArrayInt(int[] vals, int idx) { int[] newVals = new int[vals.length - 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } if (idx < newVals.length) { System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); } return newVals; } public static short[] insertArrayShort(short[] vals, short val, int idx) { short[] newVals = new short[vals.length + 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } newVals[idx] = val; if (idx < vals.length) { System.arraycopy(vals, idx, newVals, idx + 1, vals.length - idx); } return newVals; } public static short[] deleteArrayShort(short[] vals, int idx) { short[] newVals = new short[vals.length - 1]; if (idx > 0) { System.arraycopy(vals, 0, newVals, 0, idx); } if (idx < newVals.length) { System.arraycopy(vals, idx + 1, newVals, idx, newVals.length - idx); } return newVals; } /** * Paged file's header */ public abstract class FileHeader { private boolean dirty = false; private int workSize; private short headerSize; private int pageSize; private long pageCount; private long totalCount; private long firstFreePage = -1; private long lastFreePage = -1; private byte pageHeaderSize = 64; private short maxKeySize = 256; private long recordCount; public FileHeader() { this(1024); } public FileHeader(long pageCount) { this(pageCount, 4096); } public FileHeader(long pageCount, int pageSize) { this.pageSize = pageSize; this.pageCount = pageCount; totalCount = pageCount; headerSize = (short) 4096; calculateWorkSize(); } public FileHeader(boolean read) throws IOException { if (read) { read(); } } public synchronized final void read() throws IOException { RandomAccessFile raf = null; try { raf = getDescriptor(); raf.seek(0); read(raf); calculateWorkSize(); } finally { putDescriptor(raf); } } public synchronized void read(RandomAccessFile raf) throws IOException { headerSize = raf.readShort(); pageSize = raf.readInt(); pageCount = raf.readLong(); totalCount = raf.readLong(); firstFreePage = raf.readLong(); lastFreePage = raf.readLong(); pageHeaderSize = raf.readByte(); maxKeySize = raf.readShort(); recordCount = raf.readLong(); } public synchronized final void write() throws IOException { if (!dirty) { return; } RandomAccessFile raf = null; try { raf = getDescriptor(); raf.seek(0); write(raf); dirty = false; } finally { putDescriptor(raf); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -