001: /**
002: * JDBM LICENSE v1.00
003: *
004: * Redistribution and use of this software and associated documentation
005: * ("Software"), with or without modification, are permitted provided
006: * that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain copyright
009: * statements and notices. Redistributions must also contain a
010: * copy of this document.
011: *
012: * 2. Redistributions in binary form must reproduce the
013: * above copyright notice, this list of conditions and the
014: * following disclaimer in the documentation and/or other
015: * materials provided with the distribution.
016: *
017: * 3. The name "JDBM" must not be used to endorse or promote
018: * products derived from this Software without prior written
019: * permission of Cees de Groot. For written permission,
020: * please contact cg@cdegroot.com.
021: *
022: * 4. Products derived from this Software may not be called "JDBM"
023: * nor may "JDBM" appear in their names without prior written
024: * permission of Cees de Groot.
025: *
026: * 5. Due credit should be given to the JDBM Project
027: * (http://jdbm.sourceforge.net/).
028: *
029: * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
030: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
031: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
032: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
033: * CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
034: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
035: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
036: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
037: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
038: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
039: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
040: * OF THE POSSIBILITY OF SUCH DAMAGE.
041: *
042: * Copyright 2000 (C) Cees de Groot. All Rights Reserved.
043: * Contributions are Copyright (C) 2000 by their associated contributors.
044: *
045: * $Id: PageManager.java,v 1.3 2005/06/25 23:12:32 doomdark Exp $
046: */package jdbm.recman;
047:
048: import java.io.*;
049:
050: /**
051: * This class manages the linked lists of pages that make up a file.
052: */
053: final class PageManager {
054: // our record file
055: private RecordFile file;
056: // header data
057: private FileHeader header;
058: private BlockIo headerBuf;
059:
060: /**
061: * Creates a new page manager using the indicated record file.
062: */
063: PageManager(RecordFile file) throws IOException {
064: this .file = file;
065:
066: // check the file header. If the magic is 0, we assume a new
067: // file. Note that we hold on to the file header node.
068: headerBuf = file.get(0);
069: if (headerBuf.readShort(0) == 0)
070: header = new FileHeader(headerBuf, true);
071: else
072: header = new FileHeader(headerBuf, false);
073: }
074:
075: /**
076: * Allocates a page of the indicated type. Returns recid of the
077: * page.
078: */
079: long allocate(short type) throws IOException {
080:
081: if (type == Magic.FREE_PAGE)
082: throw new Error("allocate of free page?");
083:
084: // do we have something on the free list?
085: long retval = header.getFirstOf(Magic.FREE_PAGE);
086: boolean isNew = false;
087: if (retval != 0) {
088: // yes. Point to it and make the next of that page the
089: // new first free page.
090: header.setFirstOf(Magic.FREE_PAGE, getNext(retval));
091: } else {
092: // nope. make a new record
093: retval = header.getLastOf(Magic.FREE_PAGE);
094: if (retval == 0)
095: // very new file - allocate record #1
096: retval = 1;
097: header.setLastOf(Magic.FREE_PAGE, retval + 1);
098: isNew = true;
099: }
100:
101: // Cool. We have a record, add it to the correct list
102: BlockIo buf = file.get(retval);
103: PageHeader pageHdr = isNew ? new PageHeader(buf, type)
104: : PageHeader.getView(buf);
105: long oldLast = header.getLastOf(type);
106:
107: // Clean data.
108: System.arraycopy(RecordFile.cleanData, 0, buf.getData(), 0,
109: RecordFile.BLOCK_SIZE);
110: pageHdr.setType(type);
111: pageHdr.setPrev(oldLast);
112: pageHdr.setNext(0);
113:
114: if (oldLast == 0)
115: // This was the first one of this type
116: header.setFirstOf(type, retval);
117: header.setLastOf(type, retval);
118: file.release(retval, true);
119:
120: // If there's a previous, fix up its pointer
121: if (oldLast != 0) {
122: buf = file.get(oldLast);
123: pageHdr = PageHeader.getView(buf);
124: pageHdr.setNext(retval);
125: file.release(oldLast, true);
126: }
127:
128: // remove the view, we have modified the type.
129: buf.setView(null);
130:
131: return retval;
132: }
133:
134: /**
135: * Frees a page of the indicated type.
136: */
137: void free(short type, long recid) throws IOException {
138: if (type == Magic.FREE_PAGE)
139: throw new Error("free free page?");
140: if (recid == 0)
141: throw new Error("free header page?");
142:
143: // get the page and read next and previous pointers
144: BlockIo buf = file.get(recid);
145: PageHeader pageHdr = PageHeader.getView(buf);
146: long prev = pageHdr.getPrev();
147: long next = pageHdr.getNext();
148:
149: // put the page at the front of the free list.
150: pageHdr.setType(Magic.FREE_PAGE);
151: pageHdr.setNext(header.getFirstOf(Magic.FREE_PAGE));
152: pageHdr.setPrev(0);
153:
154: header.setFirstOf(Magic.FREE_PAGE, recid);
155: file.release(recid, true);
156:
157: // remove the page from its old list
158: if (prev != 0) {
159: buf = file.get(prev);
160: pageHdr = PageHeader.getView(buf);
161: pageHdr.setNext(next);
162: file.release(prev, true);
163: } else {
164: header.setFirstOf(type, next);
165: }
166: if (next != 0) {
167: buf = file.get(next);
168: pageHdr = PageHeader.getView(buf);
169: pageHdr.setPrev(prev);
170: file.release(next, true);
171: } else {
172: header.setLastOf(type, prev);
173: }
174:
175: }
176:
177: /**
178: * Returns the page following the indicated block
179: */
180: long getNext(long block) throws IOException {
181: try {
182: return PageHeader.getView(file.get(block)).getNext();
183: } finally {
184: file.release(block, false);
185: }
186: }
187:
188: /**
189: * Returns the page before the indicated block
190: */
191: long getPrev(long block) throws IOException {
192: try {
193: return PageHeader.getView(file.get(block)).getPrev();
194: } finally {
195: file.release(block, false);
196: }
197: }
198:
199: /**
200: * Returns the first page on the indicated list.
201: */
202: long getFirst(short type) throws IOException {
203: return header.getFirstOf(type);
204: }
205:
206: /**
207: * Returns the last page on the indicated list.
208: */
209: long getLast(short type) throws IOException {
210: return header.getLastOf(type);
211: }
212:
213: /**
214: * Commit all pending (in-memory) data by flushing the page manager.
215: * This forces a flush of all outstanding blocks (this it's an implicit
216: * {@link RecordFile#commit} as well).
217: */
218: void commit() throws IOException {
219: // write the header out
220: file.release(headerBuf);
221: file.commit();
222:
223: // and obtain it again
224: headerBuf = file.get(0);
225: header = new FileHeader(headerBuf, false);
226: }
227:
228: /**
229: * Flushes the page manager. This forces a flush of all outstanding
230: * blocks (this it's an implicit {@link RecordFile#commit} as well).
231: */
232: void rollback() throws IOException {
233: // release header
234: file.discard(headerBuf);
235: file.rollback();
236: // and obtain it again
237: headerBuf = file.get(0);
238: if (headerBuf.readShort(0) == 0)
239: header = new FileHeader(headerBuf, true);
240: else
241: header = new FileHeader(headerBuf, false);
242: }
243:
244: /**
245: * Closes the page manager. This flushes the page manager and releases
246: * the lock on the header.
247: */
248: void close() throws IOException {
249: file.release(headerBuf);
250: file.commit();
251: headerBuf = null;
252: header = null;
253: file = null;
254: }
255:
256: /**
257: * Returns the file header.
258: */
259: FileHeader getFileHeader() {
260: return header;
261: }
262:
263: }
|