1 24 25 package com.mckoi.database; 26 27 import com.mckoi.debug.*; 28 import com.mckoi.util.ByteArrayUtil; 29 import com.mckoi.util.UserTerminal; 30 import java.io.*; 31 import java.util.zip.*; 32 33 58 59 public class VariableSizeDataStore { 60 61 64 private final static boolean COMPRESSED_WRITE_ENABLED = true; 65 66 69 private final static int INDEX_SECTOR_SIZE = (4 * 3); 70 71 72 75 private final DebugLogger debug; 76 77 80 private FixedSizeDataStore allocation_store; 81 82 85 private FixedSizeDataStore data_store; 86 87 90 private byte[] index_key; 91 92 96 private Deflater deflater; 97 private Inflater inflater; 98 private byte[] compress_buffer; 99 100 101 102 103 106 public VariableSizeDataStore(File name, int sector_size, 107 DebugLogger logger) { 108 this.debug = logger; 109 index_key = new byte[INDEX_SECTOR_SIZE]; 110 111 String path = name.getPath(); 115 allocation_store = new FixedSizeDataStore(new File(path + ".axi"), 116 INDEX_SECTOR_SIZE, debug); 117 data_store = new FixedSizeDataStore(new File(path + ".dss"), 118 sector_size, debug); 119 } 120 121 public VariableSizeDataStore(File name, DebugLogger logger) { 122 this(name, -1, logger); 123 } 124 125 126 127 128 129 131 132 133 134 135 137 140 public void synch() throws IOException { 141 allocation_store.synch(); 142 data_store.synch(); 143 } 144 145 150 public void hardSynch() throws IOException { 151 allocation_store.hardSynch(); 152 data_store.hardSynch(); 153 } 154 155 158 public boolean locked() { 159 return allocation_store.locked(); 160 } 161 162 165 public void lock() { 166 allocation_store.lock(); 167 data_store.lock(); 168 } 169 170 173 public void unlock() { 174 data_store.unlock(); 175 allocation_store.unlock(); 176 } 177 178 179 182 public boolean recordDeleted(int record_index) throws IOException { 183 return allocation_store.isSectorDeleted(record_index); 184 } 185 186 189 public int usedRecordCount() { 190 return allocation_store.getSectorUseCount(); 191 } 192 193 197 public int rawRecordCount() throws IOException { 198 return allocation_store.rawSectorCount(); 199 } 200 201 204 public boolean exists() throws IOException { 205 return allocation_store.exists() && data_store.exists(); 206 } 207 208 211 public boolean isReadOnly() { 212 return data_store.isReadOnly(); 213 } 214 215 225 public boolean open(boolean read_only) throws IOException { 226 boolean r1 = allocation_store.open(read_only); 227 boolean r2 = data_store.open(read_only); 228 return r1 | r2; 229 } 230 231 234 public void close() throws IOException { 235 allocation_store.close(); 236 data_store.close(); 237 } 238 239 242 public void delete() { 243 allocation_store.delete(); 244 data_store.delete(); 245 } 246 247 252 public void fix(UserTerminal terminal) throws IOException { 253 terminal.println("+ Fixing variable data store."); 254 allocation_store.fix(terminal); 256 data_store.fix(terminal); 257 258 terminal.println("- Repairing references."); 259 int sector_count = allocation_store.rawSectorCount(); 263 int data_sector_count = data_store.rawSectorCount(); 264 terminal.println("- Sector count: " + sector_count); 265 int bad_record_count = 0; 268 int deleted_record_count = 0; 269 for (int i = 0; i < sector_count; ++i) { 270 if (!allocation_store.isSectorDeleted(i)) { 271 allocation_store.getSector(i, index_key); 272 int sector_head = ByteArrayUtil.getInt(index_key, 0); 273 int length = ByteArrayUtil.getInt(index_key, 4); 274 if (sector_head < 0 || sector_head >= data_sector_count || 276 length <= 0) { 277 ++bad_record_count; 278 allocation_store.deleteAcross(i); 280 ++deleted_record_count; 281 } 282 else { 283 int[] chain_span = data_store.getSectorChain(sector_head, length); 284 } 285 } 286 else { 287 ++deleted_record_count; 288 } 289 } 290 terminal.println("- Fixed " + bad_record_count + " bad chains."); 292 293 } 294 295 299 public void copyTo(File path) throws IOException { 300 allocation_store.copyTo(path); 301 data_store.copyTo(path); 302 } 303 304 311 public int writeRecordType(int record_index, int type_key) 312 throws IOException { 313 allocation_store.getSector(record_index, index_key); 316 int cur_type_key = ByteArrayUtil.getInt(index_key, 8); 318 final int old_type_key = cur_type_key; 320 type_key = (type_key & 0x0FFFFFFF0) | (cur_type_key & 0x0F); 322 ByteArrayUtil.setInt(type_key, index_key, 8); 323 allocation_store.overwriteSector(record_index, index_key); 325 326 return old_type_key; 328 } 329 330 334 public int readRecordType(int record_index) throws IOException { 335 allocation_store.getSector(record_index, index_key); 338 int cur_type_key = ByteArrayUtil.getInt(index_key, 8); 340 341 return cur_type_key; 343 } 344 345 349 public int write(byte[] buf, int offset, int length) throws IOException { 350 351 int sector_size = data_store.getSectorSize(); 354 boolean use_compressed_form = false; 355 356 int compress_size = -1; 357 if (COMPRESSED_WRITE_ENABLED) { 358 if (length > sector_size) { 359 int orig_span = data_store.calculateSectorSpan(length); 360 361 if (deflater == null) { 362 deflater = new Deflater(); 363 } 364 deflater.setInput(buf, offset, length); 365 deflater.finish(); 366 367 if (compress_buffer == null || compress_buffer.length < length + 4) { 368 compress_buffer = new byte[length + 4]; 369 } 370 compress_size = deflater.deflate(compress_buffer) + 4; 371 deflater.reset(); 372 373 int new_span = data_store.calculateSectorSpan(compress_size); 374 if (new_span < orig_span) { 375 ByteArrayUtil.setInt(length, compress_buffer, compress_size - 4); 378 use_compressed_form = true; 379 } 380 381 } 382 } 383 384 int v; 386 int real_length; 387 int type_key = 0; 388 if (use_compressed_form) { 389 v = data_store.writeAcross(compress_buffer, 0, compress_size); 390 real_length = compress_size; 391 type_key = type_key | 0x0001; 393 } 394 else { 395 v = data_store.writeAcross(buf, offset, length); 396 real_length = length; 397 } 398 ByteArrayUtil.setInt(v, index_key, 0); 401 ByteArrayUtil.setInt(real_length, index_key, 4); 402 ByteArrayUtil.setInt(type_key, index_key, 8); 403 404 return allocation_store.addSector(index_key); 406 } 407 408 413 public int read(int record, byte[] buf, int offset, int length) 414 throws IOException { 415 416 allocation_store.getSector(record, index_key); 418 int chain_head = ByteArrayUtil.getInt(index_key, 0); 420 int data_length = ByteArrayUtil.getInt(index_key, 4); 422 int type_key = ByteArrayUtil.getInt(index_key, 8); 424 425 if ((type_key & 0x0001) != 0) { 427 if (compress_buffer == null || compress_buffer.length < data_length) { 428 compress_buffer = new byte[data_length]; 429 } 430 data_store.readAcross(chain_head, compress_buffer, 0, data_length); 431 432 if (inflater == null) { 434 inflater = new Inflater(); 435 } 436 inflater.reset(); 437 inflater.setInput(compress_buffer, 0, data_length); 438 int inflate_count; 439 try { 440 inflate_count = inflater.inflate(buf, offset, length); 441 } 442 catch (DataFormatException e) { 443 e.printStackTrace(); 444 debug.writeException(e); 445 throw new Error (e.getMessage()); 446 } 447 448 return inflate_count; 449 } 450 else { 451 int read_amount = Math.min(length, data_length); 454 data_store.readAcross(chain_head, buf, offset, read_amount); 456 457 return read_amount; 458 } 459 460 } 461 462 465 public byte[] readRecord(int record) throws IOException { 466 allocation_store.getSector(record, index_key); 468 int chain_head = ByteArrayUtil.getInt(index_key, 0); 470 int data_length = ByteArrayUtil.getInt(index_key, 4); 472 int type_key = ByteArrayUtil.getInt(index_key, 8); 474 475 if ((type_key & 0x0001) != 0) { 477 if (compress_buffer == null || compress_buffer.length < data_length) { 478 compress_buffer = new byte[data_length]; 479 } 480 data_store.readAcross(chain_head, compress_buffer, 0, data_length); 481 482 if (inflater == null) { 484 inflater = new Inflater(); 485 } 486 int uncompressed_size = 488 ByteArrayUtil.getInt(compress_buffer, data_length - 4); 489 490 byte[] buf = new byte[uncompressed_size]; 491 492 inflater.reset(); 493 inflater.setInput(compress_buffer, 0, data_length - 4); 494 int inflate_count; 495 try { 496 inflate_count = inflater.inflate(buf); 497 } 498 catch (DataFormatException e) { 499 e.printStackTrace(); 500 debug.writeException(e); 501 throw new Error (e.getMessage()); 502 } 503 504 if (inflate_count != buf.length) { 505 throw new Error ("Inflate size != buf.length (" + 506 inflate_count + " != " + buf.length + ")"); 507 } 508 509 return buf; 510 } 511 else { 512 byte[] buf = new byte[data_length]; 515 data_store.readAcross(chain_head, buf, 0, data_length); 517 518 return buf; 519 } 520 521 } 522 523 526 public int delete(int record) throws IOException { 527 allocation_store.getSector(record, index_key); 529 int chain_head = ByteArrayUtil.getInt(index_key, 0); 531 532 allocation_store.deleteSector(record); 534 data_store.deleteAcross(chain_head); 536 537 return record; 538 } 539 540 private OutputStream sector_output_stream = null; 541 542 552 public OutputStream getRecordOutputStream() throws IOException { 553 if (sector_output_stream == null) { 554 sector_output_stream = data_store.getSectorOutputStream(); 555 return sector_output_stream; 556 } 557 else { 558 throw new Error ("More than one record output stream opened."); 559 } 560 } 561 562 570 public int completeRecordStreamWrite() throws IOException { 571 if (sector_output_stream != null) { 572 int v = data_store.getSectorOfLastOutputStream(); 573 int real_length = data_store.getLengthOfLastOutputStream(); 574 int type_key = 0; 575 ByteArrayUtil.setInt(v, index_key, 0); 578 ByteArrayUtil.setInt(real_length, index_key, 4); 579 ByteArrayUtil.setInt(type_key, index_key, 8); 580 581 sector_output_stream = null; 582 data_store.wipeLastOutputStream(); 583 584 return allocation_store.addSector(index_key); 586 } 587 else { 588 throw new Error ("Output stream not available."); 589 } 590 } 591 592 601 public InputStream getRecordInputStream(int record) throws IOException { 602 allocation_store.getSector(record, index_key); 604 int chain_head = ByteArrayUtil.getInt(index_key, 0); 606 607 return data_store.getSectorInputStream(chain_head); 609 } 610 611 612 613 617 public int sectorSize() throws IOException { 618 return data_store.getSectorSize(); 619 } 620 621 625 public int recordSize(int record) throws IOException { 626 allocation_store.getSector(record, index_key); 628 return ByteArrayUtil.getInt(index_key, 4); 630 } 631 632 635 public boolean isCompressed(int record) throws IOException { 636 allocation_store.getSector(record, index_key); 638 return (ByteArrayUtil.getInt(index_key, 8) & 0x0001) != 0; 640 } 641 642 646 public int recordSectorCount(int record) throws IOException { 647 return data_store.calculateSectorSpan(recordSize(record)); 650 } 651 652 656 public long totalStoreSize() { 657 return data_store.totalSize(); 658 } 659 660 664 public void writeReservedBuffer(byte[] info, int offset, int length, 665 int res_offset) throws IOException { 666 allocation_store.writeReservedBuffer(info, offset, length, res_offset); 667 } 668 669 public void writeReservedBuffer(byte[] info, int offset, int length) 670 throws IOException { 671 allocation_store.writeReservedBuffer(info, offset, length); 672 } 673 674 678 public void readReservedBuffer(byte[] info, int offset, int length) 679 throws IOException { 680 allocation_store.readReservedBuffer(info, offset, length); 681 } 682 683 684 686 690 public static boolean exists(File path, String name) throws IOException { 691 File af = new File(path, name + ".axi"); 692 File df = new File(path, name + ".dss"); 693 694 return (af.exists() & df.exists()); 695 } 696 697 700 public static boolean delete(File path, String name) throws IOException { 701 File af = new File(path, name + ".axi"); 702 File df = new File(path, name + ".dss"); 703 704 return (af.delete() & df.delete()); 705 } 706 707 710 public static boolean rename(File path_source, String name_source, 711 File path_dest, String name_dest) throws IOException { 712 File afs = new File(path_source, name_source + ".axi"); 713 File dfs = new File(path_source, name_source + ".dss"); 714 File afd = new File(path_dest, name_dest + ".axi"); 715 File dfd = new File(path_dest, name_dest + ".dss"); 716 717 return (afs.renameTo(afd) & dfs.renameTo(dfd)); 718 } 719 720 721 722 724 public int writeString(String str) throws IOException { 725 byte[] bts = str.getBytes(); 726 return write(bts, 0, bts.length); 727 } 728 729 public String readString(int record) throws IOException { 730 byte[] buffer = new byte[65536]; 731 int read_in = read(record, buffer, 0, 65536); 732 return new String (buffer, 0, read_in); 733 } 734 735 } 736 | Popular Tags |