KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > indexing > ObjectPage


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.indexing;
12
13 /**
14  An ObjectPage is a page in a page file that contains objects. Objects are byte arrays.
15  An object page contains metainformation about the objects located on that page as well
16  as information about the state of the page. This information is updated as the page
17  has objects placed on it or removed from it. Objects within a page are identified by
18  their object number, which is in the range of 1-255 inclusive.
19
20  All pages are numbered. Space map pages are located at page numbers i*(Page.Size) in
21  the page file. Object pages are located at all page numbers between space map pages.
22  Thus object pages will never have page numbers that are multiples of the page size.
23  */

24
25 class ObjectPage extends ObjectStorePage {
26
27     protected static final int MaxEntries = 256;
28     protected static final int ObjectDirectoryOffset = 64;
29     protected static final int ObjectSpaceOffset = ObjectDirectoryOffset + 512;
30     protected static final int FlagOffset = 0;
31     protected static final int UsedSpaceOffset = 2;
32     protected static final int UsedEntriesOffset = 4;
33     protected static final int InitialEntryOffset = 6;
34     protected static final int FreeSpaceOffset = 8;
35
36     public static final int ObjectSpaceSize = SIZE - ObjectSpaceOffset;
37
38     protected int usedSpace;
39     protected int usedEntries;
40     protected int freeSpaceOffset;
41     protected int initialEntry;
42
43     /**
44      * Creates a new page from a buffer.
45      */

46     public ObjectPage(int pageNumber, byte[] buffer, PageStore pageStore) {
47         super(pageNumber, buffer, pageStore);
48     }
49
50     /**
51      * Writes the contents of the page to a buffer.
52      */

53     public void toBuffer(byte[] buffer) {
54         dematerialize();
55         pageBuffer.copyTo(buffer);
56     }
57
58     /**
59      * Updates the page fields from its bytes. This is used when the page has just been mutated from
60      * a its superclass.
61      */

62
63     protected void materialize() {
64         int initialized = pageBuffer.getUInt(FlagOffset, 2);
65         if (initialized == 0xEEEE) {
66             usedSpace = pageBuffer.getUInt(UsedSpaceOffset, 2);
67             usedEntries = pageBuffer.getUInt(UsedEntriesOffset, 2);
68             initialEntry = pageBuffer.getUInt(InitialEntryOffset, 2);
69             freeSpaceOffset = pageBuffer.getUInt(FreeSpaceOffset, 2);
70         } else {
71             usedSpace = 0;
72             usedEntries = 0;
73             initialEntry = 0;
74             freeSpaceOffset = ObjectSpaceOffset;
75         }
76     }
77
78     /**
79      * Writes the object page header and from the header instance variables. This is used just before
80      * the page is to be written to the page store.
81      */

82     protected void dematerialize() {
83         pageBuffer.put(FlagOffset, 2, 0xEEEE);
84         pageBuffer.put(UsedSpaceOffset, 2, usedSpace);
85         pageBuffer.put(UsedEntriesOffset, 2, usedEntries);
86         pageBuffer.put(InitialEntryOffset, 2, initialEntry);
87         pageBuffer.put(FreeSpaceOffset, 2, freeSpaceOffset);
88     }
89
90     /**
91      * This method returns the Field mapped over the object for a given object number.
92      */

93     public Field getObjectField(int objectNumber) throws ObjectStoreException {
94         int entryOffset = ObjectDirectoryOffset + 2 * objectNumber;
95         int blockOffset = pageBuffer.getUInt(entryOffset, 2);
96         if (blockOffset == 0)
97             return null;
98         ObjectHeader header = new ObjectHeader(pageBuffer.get(blockOffset, ObjectHeader.SIZE));
99         Field f = pageBuffer.getField(blockOffset + ObjectHeader.SIZE, header.getObjectLength());
100         return f;
101     }
102
103     /**
104      * Places an object into a page. The object must have a reservation.
105      */

106     public void insertObject(StoredObject object) throws ObjectStoreException {
107
108         // ensure that there is space for this object
109
int blockLength = object.length() + ObjectHeader.SIZE;
110         if (getFreeSpace() < blockLength) {
111             throw new ObjectStoreException(ObjectStoreException.ObjectSizeFailure);
112         }
113
114         // make sure the slot is still empty
115
int objectNumber = object.getAddress().getObjectNumber();
116         int entryOffset = ObjectDirectoryOffset + (objectNumber * 2);
117         int blockOffset = pageBuffer.getUInt(entryOffset, 2);
118         if (blockOffset != 0) {
119             throw new ObjectStoreException(ObjectStoreException.PageVacancyFailure);
120         }
121
122         // place the object into the object space portion of the page
123
if (blockLength > (SIZE - freeSpaceOffset))
124             compress(); // compress the space if necessary
125
blockOffset = freeSpaceOffset; // place the object at the beginning of the free space
126
ObjectHeader header = new ObjectHeader(object.length());
127         pageBuffer.put(blockOffset, header);
128         pageBuffer.put(blockOffset + ObjectHeader.SIZE, object.toByteArray());
129         pageBuffer.put(entryOffset, 2, blockOffset);
130         freeSpaceOffset += blockLength; // update where the new free space is
131
usedSpace += blockLength; // indicate that space is used up
132
usedEntries++; // indicate that an entry is used up
133
initialEntry = (objectNumber + 1) % MaxEntries; // set where to begin the next search
134
setChanged();
135         notifyObservers();
136     }
137
138     /**
139      * Reserves space for an object on the page. Records the reservation in the
140      * reservation table.
141      */

142     public int reserveObject(StoredObject object, ReservationTable reservations) throws ObjectStoreException {
143
144         // ensure that there is space for this object, there should be since we check beforehand
145
int blockLength = object.length() + ObjectHeader.SIZE;
146         if (getFreeSpace() < blockLength) {
147             throw new ObjectStoreException(ObjectStoreException.ObjectSizeFailure);
148         }
149
150         // get the reservation for this page from the table, create a new one if necessary
151
Reservation r = reservations.get(pageNumber);
152         if (r == null) {
153             r = new Reservation(getFreeSpace(), MaxEntries - usedEntries, initialEntry);
154             reservations.put(pageNumber, r);
155         }
156
157         // find an empty slot that is not already reserved
158
int objectNumber = r.getInitialEntry();
159         int blockOffset = 0;
160         int entryOffset = 0;
161         for (int i = 0; i < MaxEntries; i++) {
162             if (!r.contains(objectNumber)) {
163                 entryOffset = ObjectDirectoryOffset + (objectNumber * 2);
164                 blockOffset = pageBuffer.getUInt(entryOffset, 2);
165                 if (blockOffset == 0)
166                     break;
167             }
168             objectNumber = (objectNumber + 1) % MaxEntries;
169         }
170         if (blockOffset != 0) {
171             throw new ObjectStoreException(ObjectStoreException.PageVacancyFailure);
172         }
173
174         // begin the next search just after where we left off
175
r.setInitialEntry((objectNumber + 1) % MaxEntries);
176
177         // update the reservation for this page
178
r.add(objectNumber, blockLength);
179         return objectNumber;
180     }
181
182     public void removeObject(int objectNumber) throws ObjectStoreException {
183
184         /* check for existence of the object to be removed */
185         int entryOffset = ObjectDirectoryOffset + 2 * objectNumber;
186         int blockOffset = pageBuffer.getUInt(entryOffset, 2);
187         if (blockOffset == 0)
188             throw new ObjectStoreException(ObjectStoreException.ObjectExistenceFailure);
189
190         /* remove the object */
191         pageBuffer.put(entryOffset, 2, 0); // remove its offset from the object table
192
ObjectHeader h = new ObjectHeader(pageBuffer.get(blockOffset, ObjectHeader.SIZE));
193         int objectLength = h.getObjectLength();
194         int blockLength = objectLength + ObjectHeader.SIZE; // find the length of it in the object space
195
pageBuffer.clear(blockOffset, blockLength); // clear its spot in the object space
196
usedSpace -= blockLength; // space has been freed
197
usedEntries--; // an entry has been freed;
198
setChanged();
199         notifyObservers();
200     }
201
202     /**
203      * Updates an object value on the page. An object may not change its size.
204      */

205     public void updateObject(StoredObject object) throws ObjectStoreException {
206
207         int objectNumber = object.getAddress().getObjectNumber();
208
209         /* check for existence of the object to be updated */
210         int entryOffset = ObjectDirectoryOffset + 2 * objectNumber;
211         int blockOffset = pageBuffer.getUInt(entryOffset, 2);
212         if (blockOffset == 0) {
213             throw new ObjectStoreException(ObjectStoreException.ObjectExistenceFailure);
214         }
215
216         /* retrieve the header and check the size */
217         ObjectHeader header = new ObjectHeader(pageBuffer.get(blockOffset, ObjectHeader.SIZE));
218         if (header.getObjectLength() != object.length()) {
219             throw new ObjectStoreException(ObjectStoreException.ObjectSizeFailure);
220         }
221
222         /* update in place */
223         int objectOffset = blockOffset + ObjectHeader.SIZE;
224         pageBuffer.put(objectOffset, object.toByteArray());
225         setChanged();
226         notifyObservers();
227     }
228
229     /**
230      * Compresses the space in the page, putting all the free space at the end of the page.
231      * This will adjust the free space offset and the offsets of the individual objects. All
232      * of the other parameters of the page remain the same. Resets the number of
233      * used entries to fix an old bug.
234      */

235     private void compress() throws ObjectStoreException {
236         Buffer temp = new Buffer(SIZE);
237         int newBlockOffset = ObjectSpaceOffset;
238         int entryOffset = ObjectDirectoryOffset;
239         usedEntries = 0;
240         for (int i = 0; i < MaxEntries; i++) {
241             int oldBlockOffset = pageBuffer.getUInt(entryOffset, 2);
242             if (oldBlockOffset > 0) {
243                 ObjectHeader h = new ObjectHeader(pageBuffer.get(oldBlockOffset, ObjectHeader.SIZE));
244                 int blockLength = h.getObjectLength() + ObjectHeader.SIZE;
245                 temp.put(newBlockOffset, pageBuffer.get(oldBlockOffset, blockLength));
246                 pageBuffer.put(entryOffset, 2, newBlockOffset);
247                 newBlockOffset += blockLength;
248                 usedEntries++;
249             }
250             entryOffset += 2;
251         }
252         pageBuffer.put(ObjectSpaceOffset, temp.get(ObjectSpaceOffset, SIZE - ObjectSpaceOffset));
253         freeSpaceOffset = newBlockOffset;
254     }
255
256     /**
257      * Returns the amount of free space on this page.
258      */

259     public int getFreeSpace() {
260         if (usedEntries >= MaxEntries)
261             return 0;
262         return SIZE - (ObjectSpaceOffset + usedSpace);
263     }
264 }
265
Popular Tags