001: // Spatial Index Library
002: //
003: // Copyright (C) 2002 Navel Ltd.
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: //
019: // Contact information:
020: // Mailing address:
021: // Marios Hadjieleftheriou
022: // University of California, Riverside
023: // Department of Computer Science
024: // Surge Building, Room 310
025: // Riverside, CA 92521
026: //
027: // Email:
028: // marioh@cs.ucr.edu
029: package org.geotools.caching.spatialindex.storagemanager;
030:
031: import java.io.*;
032:
033: import java.util.*;
034:
035: public class DiskStorageManager implements IStorageManager {
036: private RandomAccessFile m_dataFile = null;
037: private RandomAccessFile m_indexFile = null;
038: private int m_pageSize = 0;
039: private int m_nextPage = -1;
040: private TreeSet m_emptyPages = new TreeSet();
041: private HashMap m_pageIndex = new HashMap();
042: private byte[] m_buffer = null;
043:
044: public DiskStorageManager(PropertySet ps) throws SecurityException,
045: NullPointerException, IOException, FileNotFoundException,
046: IllegalArgumentException {
047: Object var;
048:
049: // Open/Create flag.
050: boolean bOverwrite = false;
051: var = ps.getProperty("Overwrite");
052:
053: if (var != null) {
054: if (!(var instanceof Boolean)) {
055: throw new IllegalArgumentException(
056: "Property Overwrite must be a Boolean");
057: }
058:
059: bOverwrite = ((Boolean) var).booleanValue();
060: }
061:
062: // storage filename.
063: var = ps.getProperty("FileName");
064:
065: if (var != null) {
066: if (!(var instanceof String)) {
067: throw new IllegalArgumentException(
068: "Property FileName must be a String");
069: }
070:
071: File indexFile = new File((String) var + ".idx");
072: File dataFile = new File((String) var + ".dat");
073:
074: // check if files exist.
075: if ((bOverwrite == false)
076: && (!indexFile.exists() || !dataFile.exists())) {
077: bOverwrite = true;
078: }
079:
080: if (bOverwrite) {
081: if (indexFile.exists()) {
082: indexFile.delete();
083: }
084:
085: if (dataFile.exists()) {
086: dataFile.delete();
087: }
088:
089: boolean b = indexFile.createNewFile();
090:
091: if (b == false) {
092: throw new IOException(
093: "Index file cannot be opened.");
094: }
095:
096: b = dataFile.createNewFile();
097:
098: if (b == false) {
099: throw new IOException("Data file cannot be opened.");
100: }
101: }
102:
103: m_indexFile = new RandomAccessFile(indexFile, "rw");
104: m_dataFile = new RandomAccessFile(dataFile, "rw");
105: } else {
106: throw new IllegalArgumentException(
107: "Property FileName was not specified.");
108: }
109:
110: // find page size.
111: if (bOverwrite == true) {
112: var = ps.getProperty("PageSize");
113:
114: if (var != null) {
115: if (!(var instanceof Integer)) {
116: throw new IllegalArgumentException(
117: "Property PageSize must be an Integer");
118: }
119:
120: m_pageSize = ((Integer) var).intValue();
121: m_nextPage = 0;
122: } else {
123: throw new IllegalArgumentException(
124: "Property PageSize was not specified.");
125: }
126: } else {
127: try {
128: m_pageSize = m_indexFile.readInt();
129: } catch (EOFException ex) {
130: throw new IllegalStateException(
131: "Failed reading pageSize.");
132: }
133:
134: try {
135: m_nextPage = m_indexFile.readInt();
136: } catch (EOFException ex) {
137: throw new IllegalStateException(
138: "Failed reading nextPage.");
139: }
140: }
141:
142: // create buffer.
143: m_buffer = new byte[m_pageSize];
144:
145: if (bOverwrite == false) {
146: int count;
147: int id;
148: int page;
149:
150: // load empty pages in memory.
151: try {
152: count = m_indexFile.readInt();
153:
154: for (int cCount = 0; cCount < count; cCount++) {
155: page = m_indexFile.readInt();
156: m_emptyPages.add(new Integer(page));
157: }
158:
159: // load index table in memory.
160: count = m_indexFile.readInt();
161:
162: for (int cCount = 0; cCount < count; cCount++) {
163: Entry e = new Entry();
164:
165: id = m_indexFile.readInt();
166: e.m_length = m_indexFile.readInt();
167:
168: int count2 = m_indexFile.readInt();
169:
170: for (int cCount2 = 0; cCount2 < count2; cCount2++) {
171: page = m_indexFile.readInt();
172: e.m_pages.add(new Integer(page));
173: }
174:
175: m_pageIndex.put(new Integer(id), e);
176: }
177: } catch (EOFException ex) {
178: throw new IllegalStateException("Corrupted index file.");
179: }
180: }
181: }
182:
183: public void flush() {
184: try {
185: m_indexFile.seek(0L);
186:
187: m_indexFile.writeInt(m_pageSize);
188: m_indexFile.writeInt(m_nextPage);
189:
190: int id;
191: int page;
192: int count = m_emptyPages.size();
193:
194: m_indexFile.writeInt(count);
195:
196: Iterator it = m_emptyPages.iterator();
197:
198: while (it.hasNext()) {
199: page = ((Integer) it.next()).intValue();
200: m_indexFile.writeInt(page);
201: }
202:
203: count = m_pageIndex.size();
204: m_indexFile.writeInt(count);
205:
206: it = m_pageIndex.entrySet().iterator();
207:
208: while (it.hasNext()) {
209: Map.Entry me = (Map.Entry) it.next();
210: id = ((Integer) me.getKey()).intValue();
211: m_indexFile.writeInt(id);
212:
213: Entry e = (Entry) me.getValue();
214: count = e.m_length;
215: m_indexFile.writeInt(count);
216:
217: count = e.m_pages.size();
218: m_indexFile.writeInt(count);
219:
220: for (int cIndex = 0; cIndex < count; cIndex++) {
221: page = ((Integer) e.m_pages.get(cIndex)).intValue();
222: m_indexFile.writeInt(page);
223: }
224: }
225: } catch (IOException ex) {
226: throw new IllegalStateException("Corrupted index file.");
227: }
228: }
229:
230: public byte[] loadByteArray(final int id) {
231: Entry e = (Entry) m_pageIndex.get(new Integer(id));
232:
233: if (e == null) {
234: throw new InvalidPageException(id);
235: }
236:
237: int cNext = 0;
238: int cTotal = e.m_pages.size();
239:
240: byte[] data = new byte[e.m_length];
241: int cIndex = 0;
242: int cLen;
243: int cRem = e.m_length;
244:
245: do {
246: try {
247: m_dataFile.seek(((Integer) e.m_pages.get(cNext))
248: .intValue()
249: * m_pageSize);
250:
251: int bytesread = m_dataFile.read(m_buffer);
252:
253: if (bytesread != m_pageSize) {
254: throw new IllegalStateException(
255: "Corrupted data file.");
256: }
257: } catch (IOException ex) {
258: throw new IllegalStateException("Corrupted data file.");
259: }
260:
261: cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
262: System.arraycopy(m_buffer, 0, data, cIndex, cLen);
263:
264: cIndex += cLen;
265: cRem -= cLen;
266: cNext++;
267: } while (cNext < cTotal);
268:
269: return data;
270: }
271:
272: public int storeByteArray(final int id, final byte[] data) {
273: if (id == NewPage) {
274: Entry e = new Entry();
275: e.m_length = data.length;
276:
277: int cIndex = 0;
278: int cPage;
279: int cRem = data.length;
280: int cLen;
281:
282: while (cRem > 0) {
283: if (!m_emptyPages.isEmpty()) {
284: Integer i = (Integer) m_emptyPages.first();
285: m_emptyPages.remove(i);
286: cPage = i.intValue();
287: } else {
288: cPage = m_nextPage;
289: m_nextPage++;
290: }
291:
292: cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
293: System.arraycopy(data, cIndex, m_buffer, 0, cLen);
294:
295: try {
296: m_dataFile.seek(cPage * m_pageSize);
297: m_dataFile.write(m_buffer);
298: } catch (IOException ex) {
299: throw new IllegalStateException(
300: "Corrupted data file.");
301: }
302:
303: cIndex += cLen;
304: cRem -= cLen;
305: e.m_pages.add(new Integer(cPage));
306: }
307:
308: Integer i = (Integer) e.m_pages.get(0);
309: m_pageIndex.put(i, e);
310:
311: return i.intValue();
312: } else {
313: // find the entry.
314: Entry oldEntry = (Entry) m_pageIndex.get(new Integer(id));
315:
316: if (oldEntry == null) {
317: throw new InvalidPageException(id);
318: }
319:
320: m_pageIndex.remove(new Integer(id));
321:
322: Entry e = new Entry();
323: e.m_length = data.length;
324:
325: int cIndex = 0;
326: int cPage;
327: int cRem = data.length;
328: int cLen;
329: int cNext = 0;
330:
331: while (cRem > 0) {
332: if (cNext < oldEntry.m_pages.size()) {
333: cPage = ((Integer) oldEntry.m_pages.get(cNext))
334: .intValue();
335: cNext++;
336: } else if (!m_emptyPages.isEmpty()) {
337: Integer i = (Integer) m_emptyPages.first();
338: m_emptyPages.remove(i);
339: cPage = i.intValue();
340: } else {
341: cPage = m_nextPage;
342: m_nextPage++;
343: }
344:
345: cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
346: System.arraycopy(data, cIndex, m_buffer, 0, cLen);
347:
348: try {
349: m_dataFile.seek(cPage * m_pageSize);
350: m_dataFile.write(m_buffer);
351: } catch (IOException ex) {
352: throw new IllegalStateException(
353: "Corrupted data file.");
354: }
355:
356: cIndex += cLen;
357: cRem -= cLen;
358: e.m_pages.add(new Integer(cPage));
359: }
360:
361: while (cNext < oldEntry.m_pages.size()) {
362: m_emptyPages.add(oldEntry.m_pages.get(cNext));
363: cNext++;
364: }
365:
366: Integer i = (Integer) e.m_pages.get(0);
367: m_pageIndex.put(i, e);
368:
369: return i.intValue();
370: }
371: }
372:
373: public void deleteByteArray(final int id) {
374: // find the entry.
375: Entry e = (Entry) m_pageIndex.get(new Integer(id));
376:
377: if (e == null) {
378: throw new InvalidPageException(id);
379: }
380:
381: m_pageIndex.remove(new Integer(id));
382:
383: for (int cIndex = 0; cIndex < e.m_pages.size(); cIndex++) {
384: m_emptyPages.add(e.m_pages.get(cIndex));
385: }
386: }
387:
388: public void close() {
389: flush();
390: }
391:
392: class Entry {
393: int m_length = 0;
394: ArrayList m_pages = new ArrayList();
395: }
396: }
|