1 30 31 32 package org.hsqldb.persist; 33 34 import java.io.EOFException ; 35 import java.io.FileNotFoundException ; 36 import java.io.IOException ; 37 import java.io.RandomAccessFile ; 38 import java.lang.reflect.Constructor ; 39 40 import org.hsqldb.Database; 41 import org.hsqldb.Trace; 42 import org.hsqldb.lib.HsqlByteArrayInputStream; 43 import org.hsqldb.lib.SimpleLog; 44 import org.hsqldb.lib.Storage; 45 46 49 57 class ScaledRAFile implements ScaledRAInterface { 58 59 static final int DATA_FILE_RAF = 0; 60 static final int DATA_FILE_NIO = 1; 61 static final int DATA_FILE_JAR = 2; 62 static final long MAX_NIO_LENGTH = (1L << 28); 63 64 final SimpleLog appLog; 66 final RandomAccessFile file; 67 private final boolean readOnly; 68 final String fileName; 69 boolean isNio; 70 boolean bufferDirty = true; 71 final byte[] buffer; 72 final HsqlByteArrayInputStream ba; 73 long bufferOffset; 74 75 long seekPosition; 77 long realPosition; 78 static int cacheHit; 79 80 84 static Storage newScaledRAFile(Database database, String name, 85 boolean readonly, int type, 86 String classname, 87 String key) 88 throws FileNotFoundException , IOException { 89 90 if (classname != null) { 91 try { 92 Class zclass = Class.forName(classname); 93 Constructor constructor = zclass.getConstructor(new Class [] { 94 String .class, Boolean .class, Object .class 95 }); 96 97 return (Storage) constructor.newInstance(new Object [] { 98 name, new Boolean (readonly), key 99 }); 100 } catch (ClassNotFoundException e) { 101 throw new IOException (); 102 } catch (NoSuchMethodException e) { 103 throw new IOException (); 104 } catch (InstantiationException e) { 105 throw new IOException (); 106 } catch (IllegalAccessException e) { 107 throw new IOException (); 108 } catch (java.lang.reflect.InvocationTargetException e) { 109 throw new IOException (); 110 } 111 } 112 113 if (type == DATA_FILE_JAR) { 114 return new ScaledRAFileInJar(name); 115 } else if (type == DATA_FILE_RAF) { 116 return new ScaledRAFile(database, name, readonly); 117 } else { 118 RandomAccessFile file = new RandomAccessFile (name, readonly ? "r" 119 : "rw"); 120 121 if (file.length() > MAX_NIO_LENGTH) { 122 return new ScaledRAFile(database, name, file, readonly); 123 } else { 124 file.close(); 125 } 126 127 try { 128 Class.forName("java.nio.MappedByteBuffer"); 129 130 Class c = 131 Class.forName("org.hsqldb.persist.ScaledRAFileHybrid"); 132 Constructor constructor = c.getConstructor(new Class [] { 133 Database.class, String .class, boolean.class 134 }); 135 136 return (ScaledRAInterface) constructor.newInstance( 137 new Object [] { 138 database, name, new Boolean (readonly) 139 }); 140 } catch (Exception e) { 141 return new ScaledRAFile(database, name, readonly); 142 } 143 } 144 } 145 146 ScaledRAFile(Database database, String name, RandomAccessFile file, 147 boolean readonly) throws FileNotFoundException , IOException { 148 149 this.appLog = database.logger.appLog; 150 this.readOnly = readonly; 151 this.fileName = name; 152 this.file = file; 153 154 int bufferScale = database.getProperties().getIntegerProperty( 155 HsqlDatabaseProperties.hsqldb_raf_buffer_scale, 12, 8, 13); 156 int bufferSize = 1 << bufferScale; 157 158 buffer = new byte[bufferSize]; 159 ba = new HsqlByteArrayInputStream(buffer); 160 } 161 162 ScaledRAFile(Database database, String name, 163 boolean readonly) throws FileNotFoundException , IOException { 164 165 this.appLog = database.logger.appLog; 166 this.readOnly = readonly; 167 this.fileName = name; 168 this.file = new RandomAccessFile (name, readonly ? "r" 169 : "rw"); 170 171 int bufferScale = database.getProperties().getIntegerProperty( 172 HsqlDatabaseProperties.hsqldb_raf_buffer_scale, 12); 173 int bufferSize = 1 << bufferScale; 174 175 buffer = new byte[bufferSize]; 176 ba = new HsqlByteArrayInputStream(buffer); 177 } 178 179 public long length() throws IOException { 180 return file.length(); 181 } 182 183 188 public void seek(long position) throws IOException { 189 190 if (!readOnly && file.length() < position) { 191 long tempSize = position - file.length(); 192 193 if (tempSize > 1 << 18) { 194 tempSize = 1 << 18; 195 } 196 197 byte[] temp = new byte[(int) tempSize]; 198 199 try { 200 long pos = file.length(); 201 202 for (; pos < position - tempSize; pos += tempSize) { 203 file.seek(pos); 204 file.write(temp, 0, (int) tempSize); 205 } 206 207 file.seek(pos); 208 file.write(temp, 0, (int) (position - pos)); 209 210 realPosition = position; 211 } catch (IOException e) { 212 appLog.logContext(e, null); 213 214 throw e; 215 } 216 } 217 218 seekPosition = position; 219 } 220 221 public long getFilePointer() throws IOException { 222 return seekPosition; 223 } 224 225 private void readIntoBuffer() throws IOException { 226 227 long filePos = seekPosition; 228 long subOffset = filePos % buffer.length; 229 long fileLength = file.length(); 230 long readLength = fileLength - (filePos - subOffset); 231 232 try { 233 if (readLength <= 0) { 234 throw new IOException ("read beyond end of file"); 235 } 236 237 if (readLength > buffer.length) { 238 readLength = buffer.length; 239 } 240 241 file.seek(filePos - subOffset); 242 file.readFully(buffer, 0, (int) readLength); 243 244 bufferOffset = filePos - subOffset; 245 realPosition = bufferOffset + readLength; 246 bufferDirty = false; 247 } catch (IOException e) { 248 resetPointer(); 249 appLog.logContext(e, "" + realPosition + " " + readLength); 250 251 throw e; 252 } 253 } 254 255 public int read() throws IOException { 256 257 try { 258 long fileLength = file.length(); 259 260 if (seekPosition >= fileLength) { 261 return -1; 262 } 263 264 if (bufferDirty || seekPosition < bufferOffset 265 || seekPosition >= bufferOffset + buffer.length) { 266 readIntoBuffer(); 267 } else { 268 cacheHit++; 269 } 270 271 ba.reset(); 272 ba.skip(seekPosition - bufferOffset); 273 274 int val = ba.read(); 275 276 seekPosition++; 277 278 return val; 279 } catch (IOException e) { 280 resetPointer(); 281 appLog.logContext(e, null); 282 283 throw e; 284 } 285 } 286 287 public long readLong() throws IOException { 288 289 try { 290 if (bufferDirty || seekPosition < bufferOffset 291 || seekPosition >= bufferOffset + buffer.length) { 292 readIntoBuffer(); 293 } else { 294 cacheHit++; 295 } 296 297 ba.reset(); 298 299 if (seekPosition - bufferOffset 300 != ba.skip(seekPosition - bufferOffset)) { 301 throw new EOFException (); 302 } 303 304 long val; 305 306 try { 307 val = ba.readLong(); 308 } catch (EOFException e) { 309 file.seek(seekPosition); 310 311 val = file.readLong(); 312 realPosition = file.getFilePointer(); 313 } 314 315 seekPosition += 8; 316 317 return val; 318 } catch (IOException e) { 319 resetPointer(); 320 appLog.logContext(e, null); 321 322 throw e; 323 } 324 } 325 326 public int readInt() throws IOException { 327 328 try { 329 if (bufferDirty || seekPosition < bufferOffset 330 || seekPosition >= bufferOffset + buffer.length) { 331 readIntoBuffer(); 332 } else { 333 cacheHit++; 334 } 335 336 ba.reset(); 337 338 if (seekPosition - bufferOffset 339 != ba.skip(seekPosition - bufferOffset)) { 340 throw new EOFException (); 341 } 342 343 int val; 344 345 try { 346 val = ba.readInt(); 347 } catch (EOFException e) { 348 file.seek(seekPosition); 349 350 val = file.readInt(); 351 realPosition = file.getFilePointer(); 352 } 353 354 seekPosition += 4; 355 356 return val; 357 } catch (IOException e) { 358 resetPointer(); 359 appLog.logContext(e, null); 360 361 throw e; 362 } 363 } 364 365 public void read(byte[] b, int offset, int length) throws IOException { 366 367 try { 368 if (bufferDirty || seekPosition < bufferOffset 369 || seekPosition >= bufferOffset + buffer.length) { 370 readIntoBuffer(); 371 } else { 372 cacheHit++; 373 } 374 375 ba.reset(); 376 377 if (seekPosition - bufferOffset 378 != ba.skip(seekPosition - bufferOffset)) { 379 throw new EOFException (); 380 } 381 382 int bytesRead = ba.read(b, offset, length); 383 384 seekPosition += bytesRead; 385 386 if (bytesRead < length) { 387 if (seekPosition != realPosition) { 388 file.seek(seekPosition); 389 } 390 391 file.readFully(b, offset + bytesRead, length - bytesRead); 392 393 seekPosition += (length - bytesRead); 394 realPosition = seekPosition; 395 } 396 } catch (IOException e) { 397 resetPointer(); 398 appLog.logContext(e, null); 399 400 throw e; 401 } 402 } 403 404 public void write(byte[] b, int off, int len) throws IOException { 405 406 try { 407 if (realPosition != seekPosition) { 408 file.seek(seekPosition); 409 410 realPosition = seekPosition; 411 } 412 413 if (seekPosition >= bufferOffset 414 && seekPosition < bufferOffset + buffer.length) { 415 bufferDirty = true; 416 } 417 418 file.write(b, off, len); 419 420 seekPosition += len; 421 realPosition = seekPosition; 422 } catch (IOException e) { 423 resetPointer(); 424 appLog.logContext(e, null); 425 426 throw e; 427 } 428 } 429 430 public void writeInt(int i) throws IOException { 431 432 try { 433 if (realPosition != seekPosition) { 434 file.seek(seekPosition); 435 436 realPosition = seekPosition; 437 } 438 439 if (seekPosition >= bufferOffset 440 && seekPosition < bufferOffset + buffer.length) { 441 bufferDirty = true; 442 } 443 444 file.writeInt(i); 445 446 seekPosition += 4; 447 realPosition = seekPosition; 448 } catch (IOException e) { 449 resetPointer(); 450 appLog.logContext(e, null); 451 452 throw e; 453 } 454 } 455 456 public void writeLong(long i) throws IOException { 457 458 try { 459 if (realPosition != seekPosition) { 460 file.seek(seekPosition); 461 462 realPosition = seekPosition; 463 } 464 465 if (seekPosition >= bufferOffset 466 && seekPosition < bufferOffset + buffer.length) { 467 bufferDirty = true; 468 } 469 470 file.writeLong(i); 471 472 seekPosition += 8; 473 realPosition = seekPosition; 474 } catch (IOException e) { 475 resetPointer(); 476 appLog.logContext(e, null); 477 478 throw e; 479 } 480 } 481 482 public void close() throws IOException { 483 Trace.printSystemOut("cache hit " + cacheHit); 484 file.close(); 485 } 486 487 public boolean isReadOnly() { 488 return readOnly; 489 } 490 491 public boolean wasNio() { 492 return false; 493 } 494 495 public boolean canAccess(int length) { 496 return true; 497 } 498 499 public boolean canSeek(long position) { 500 return true; 501 } 502 503 public Database getDatabase() { 504 return null; 505 } 506 507 private void resetPointer() { 508 509 try { 510 bufferDirty = true; 511 512 file.seek(seekPosition); 513 514 realPosition = seekPosition; 515 } catch (Throwable e) {} 516 } 517 } 518 | Popular Tags |