001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/io/rtree/PersistentPageFile.java $ 002 // 003 //RTree implementation. 004 //Copyright (C) 2002-2004 Wolfgang Baer - WBaer@gmx.de 005 // 006 //This library is free software; you can redistribute it and/or 007 //modify it under the terms of the GNU Lesser General Public 008 //License as published by the Free Software Foundation; either 009 //version 2.1 of the License, or (at your option) any later version. 010 // 011 //This library is distributed in the hope that it will be useful, 012 //but WITHOUT ANY WARRANTY; without even the implied warranty of 013 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 //Lesser General Public License for more details. 015 // 016 //You should have received a copy of the GNU Lesser General Public 017 //License along with this library; if not, write to the Free Software 018 //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 019 020 package org.deegree.io.rtree; 021 022 import java.io.ByteArrayInputStream; 023 import java.io.ByteArrayOutputStream; 024 import java.io.DataInputStream; 025 import java.io.DataOutputStream; 026 import java.io.EOFException; 027 import java.io.File; 028 import java.io.IOException; 029 import java.io.RandomAccessFile; 030 import java.util.Stack; 031 032 /** 033 * <p> 034 * A persistent implementation of a PageFile implemented based on a RandomAccesFile. 035 * </p> 036 * <p> 037 * Structure of the File<br> 038 * <br> 039 * <br> -- Header --<br> 040 * int pageFileVersion<br> 041 * int dimension<br> 042 * int capacity = maxLoad + 1 for Overflow<br> 043 * int minimum<br> 044 * <br> 045 * <br> -- Body --<br> 046 * a sequence of page one after another with:<br> 047 * int typ - 1 LeafNode 2 NoneLeafNode<br> 048 * int place - index of entry of this node in father node<br> 049 * int counter - current used space in the node<br> 050 * int parentNode - page number of father node<br> 051 * int pageNumber - own page number<br> - for(i = 0; i < capacity; i++)<br> 052 * int data Entry i - page number of childnode or object ID of data entry<br> - always dependend on 053 * dimension = x<br> 054 * double pMin x.Dimension - pMin of the common HyperBoundingBox<br> 055 * double pMax x.Dimension - pMax of the common HyperBoundingBox<br> - for(i = 0; i < capacity; 056 * i++)<br> 057 * double pMin x.Dimension - pMin HyperBoundingBox for Entry i<br> 058 * double pMax x.Dimension - pMax HyperBoundingBox for Entry i<br> 059 * <br> 060 * <br> 061 * int entspr. 4 Bytes - double entspr. 8 Bytes<br> 062 * <br> 063 * <br> 064 * PageSize = (4 * (5 + capacity)) + (capacity + 1) * (dimension * 16)<br> 065 * <br> 066 * </p> 067 * 068 * @author Wolfgang Baer - WBaer@gmx.de 069 */ 070 class PersistentPageFile extends PageFile { 071 072 /** magic number */ 073 private static final int PAGEFILE_VERSION = 060676002; 074 075 private static final int EMPTY_PAGE = -22; 076 077 private RandomAccessFile file; 078 079 private int pageSize; 080 081 private String fileName; 082 083 private byte[] buffer; 084 085 private Stack<Integer> emptyPages; 086 087 private boolean closed; 088 089 /** 090 * Constructor 091 * 092 * @param fileName 093 */ 094 protected PersistentPageFile( String fileName ) { 095 super(); 096 this.fileName = fileName; 097 this.emptyPages = new Stack<Integer>(); 098 this.closed = false; 099 } 100 101 /** 102 * Initializes the PersistentPageFile. Overrides initialize in PageFile. 103 * 104 * @param dimension - 105 * dimension of the data 106 * @param capacity - 107 * capacity of a node 108 * @throws PageFileException 109 */ 110 protected void initialize( int dimension, int capacity ) 111 throws PageFileException { 112 super.initialize( dimension, capacity ); 113 114 File fileTest = new File( fileName ); 115 116 try { 117 if ( dimension == -999 ) { 118 // Initialize from existing file 119 120 if ( !fileTest.exists() ) 121 throw new PageFileException( "File does not exist" ); 122 123 file = new RandomAccessFile( fileTest, "rw" ); 124 // Test if it is a PersistentPageFile 125 file.seek( 0 ); 126 if ( file.readInt() != PAGEFILE_VERSION ) 127 throw new PageFileException( "Not a PersistentPageFile or wrong version" ); 128 129 // Reading header - Initializing PageFile 130 this.dimension = file.readInt(); 131 this.capacity = file.readInt(); 132 this.minimum = file.readInt(); 133 this.pageSize = ( ( 4 * ( 5 + this.capacity ) ) + ( ( this.capacity + 1 ) * ( this.dimension * 16 ) ) ); 134 this.buffer = new byte[pageSize]; 135 136 // reading empty pages in Stack 137 int i = 0; 138 try { 139 while ( true ) { 140 file.seek( 16 + ( i * pageSize ) ); 141 if ( EMPTY_PAGE == file.readInt() ) 142 emptyPages.push( new Integer( i ) ); 143 i++; 144 } 145 } catch ( EOFException eof ) { // not an exception - wanted 146 } 147 } else { 148 // new file 149 file = new RandomAccessFile( fileTest, "rw" ); 150 file.setLength( 0 ); 151 this.pageSize = ( ( 4 * ( 5 + capacity ) ) + ( ( capacity + 1 ) * ( dimension * 16 ) ) ); 152 this.buffer = new byte[pageSize]; 153 154 // writing header 155 file.seek( 0 ); 156 file.writeInt( PAGEFILE_VERSION ); 157 file.writeInt( this.dimension ); 158 file.writeInt( this.capacity ); 159 file.writeInt( this.minimum ); 160 161 } 162 } catch ( IOException e ) { 163 e.fillInStackTrace(); 164 throw new PageFileException( "IOException occured: \n " + e.getMessage() ); 165 } 166 } 167 168 /** 169 * @see PageFile#readNode(int) 170 */ 171 protected Node readNode( int pageFileNumber ) 172 throws PageFileException { 173 174 Node node = null; 175 176 try { 177 file.seek( 16 + ( pageFileNumber * pageSize ) ); 178 179 int read = file.read( buffer ); 180 181 if ( pageSize == read ) { 182 183 DataInputStream ds = new DataInputStream( new ByteArrayInputStream( buffer ) ); 184 185 int type = ds.readInt(); 186 if ( type == 1 ) 187 node = new LeafNode( -1, this ); 188 else 189 node = new NoneLeafNode( -1, this ); 190 191 node.place = ds.readInt(); 192 node.counter = ds.readInt(); 193 node.parentNode = ds.readInt(); 194 node.pageNumber = ds.readInt(); 195 196 if ( type == 1 ) { 197 for ( int i = 0; i < capacity; i++ ) 198 ( (LeafNode) node ).data[i] = ds.readInt(); 199 } else { 200 for ( int i = 0; i < capacity; i++ ) 201 ( (NoneLeafNode) node ).childNodes[i] = ds.readInt(); 202 } 203 204 node.unionMinBB = readNextHyperBoundingBox( ds ); 205 206 for ( int i = 0; i < capacity; i++ ) 207 node.hyperBBs[i] = readNextHyperBoundingBox( ds ); 208 209 ds.close(); 210 } else { 211 throw new PageFileException( "Exception during read operation" ); 212 } 213 214 return node; 215 216 } catch ( IOException e ) { 217 e.fillInStackTrace(); 218 throw new PageFileException( "PageFileException occured ! \n " + e.getMessage() ); 219 } 220 } 221 222 // reads the next HyperBoundingBox from the byte buffer 223 private HyperBoundingBox readNextHyperBoundingBox( DataInputStream ds ) 224 throws IOException { 225 226 double[] point1, point2; 227 point1 = new double[dimension]; 228 point2 = new double[dimension]; 229 230 for ( int i = 0; i < dimension; i++ ) 231 point1[i] = ds.readDouble(); 232 233 for ( int i = 0; i < dimension; i++ ) 234 point2[i] = ds.readDouble(); 235 236 return new HyperBoundingBox( new HyperPoint( point1 ), new HyperPoint( point2 ) ); 237 } 238 239 /** 240 * @see PageFile#writeNode(Node) 241 */ 242 protected int writeNode( Node node ) 243 throws PageFileException { 244 try { 245 246 if ( node.pageNumber < 0 ) { 247 if ( !emptyPages.empty() ) 248 node.setPageNumber( emptyPages.pop() ); 249 else 250 node.setPageNumber( (int) ( ( file.length() - 16 ) / pageSize ) ); 251 } 252 253 ByteArrayOutputStream bs = new ByteArrayOutputStream( pageSize ); 254 DataOutputStream ds = new DataOutputStream( bs ); 255 256 int type; 257 if ( node instanceof LeafNode ) 258 type = 1; 259 else 260 type = 2; 261 262 ds.writeInt( type ); 263 264 ds.writeInt( node.place ); 265 ds.writeInt( node.counter ); 266 ds.writeInt( node.parentNode ); 267 ds.writeInt( node.pageNumber ); 268 269 if ( node instanceof LeafNode ) { 270 for ( int i = 0; i < node.counter; i++ ) { 271 ds.writeInt( ( (LeafNode) node ).data[i] ); 272 } 273 for ( int i = 0; i < ( capacity - node.counter ); i++ ) 274 ds.writeInt( -1 ); 275 } else { 276 for ( int i = 0; i < node.counter; i++ ) { 277 ds.writeInt( ( (NoneLeafNode) node ).childNodes[i] ); 278 } 279 280 for ( int i = 0; i < ( capacity - node.counter ); i++ ) 281 ds.writeInt( -1 ); 282 } 283 284 for ( int i = 0; i < dimension; i++ ) 285 ds.writeDouble( node.unionMinBB.getPMin().getCoord( i ) ); 286 287 for ( int i = 0; i < dimension; i++ ) 288 ds.writeDouble( node.unionMinBB.getPMax().getCoord( i ) ); 289 290 for ( int j = 0; j < node.counter; j++ ) { 291 for ( int i = 0; i < dimension; i++ ) 292 ds.writeDouble( node.hyperBBs[j].getPMin().getCoord( i ) ); 293 294 for ( int i = 0; i < dimension; i++ ) 295 ds.writeDouble( node.hyperBBs[j].getPMax().getCoord( i ) ); 296 } 297 298 for ( int j = 0; j < ( capacity - node.counter ); j++ ) { 299 for ( int i = 0; i < ( dimension * 2 ); i++ ) 300 ds.writeDouble( -1 ); 301 } 302 303 ds.flush(); 304 bs.flush(); 305 306 file.seek( 16 + ( pageSize * node.pageNumber ) ); 307 308 file.write( bs.toByteArray() ); 309 310 ds.close(); 311 312 return node.pageNumber; 313 314 } catch ( IOException e ) { 315 e.fillInStackTrace(); 316 throw new PageFileException( "PageFileException occured ! \n " + e.getMessage() ); 317 } 318 } 319 320 /** 321 * @see PageFile#deleteNode(int) 322 */ 323 protected Node deleteNode( int pageNumber ) 324 throws PageFileException { 325 Node node = this.readNode( pageNumber ); 326 try { 327 file.seek( 16 + ( pageSize * node.pageNumber ) ); 328 file.writeInt( EMPTY_PAGE ); 329 } catch ( IOException e ) { 330 e.fillInStackTrace(); 331 throw new PageFileException( "PageFileException occured ! \n " + e.getMessage() ); 332 } 333 334 emptyPages.push( new Integer( pageNumber ) ); 335 return node; 336 } 337 338 /** 339 * @see PageFile#close() 340 */ 341 protected void close() 342 throws PageFileException { 343 try { 344 file.close(); 345 } catch ( IOException e ) { 346 e.fillInStackTrace(); 347 throw new PageFileException( "PageFileException during close()" ); 348 } 349 350 closed = true; 351 } 352 353 protected void finalize() 354 throws Throwable { 355 if ( !closed ) 356 file.close(); 357 358 super.finalize(); 359 } 360 }