1 24 25 package com.mckoi.database; 26 27 import java.io.*; 28 import java.util.Arrays ; 29 import com.mckoi.util.ByteArrayUtil; 30 import com.mckoi.util.IntegerVector; 31 import com.mckoi.util.UserTerminal; 32 import com.mckoi.util.Cache; 33 import com.mckoi.debug.*; 34 35 66 67 public final class FixedSizeDataStore { 68 69 73 private final static int MAGIC = 0x0badbead; 74 75 78 private final static int SECTOR_DATA_OFFSET = 512; 79 80 84 private final static int EXTRA_SECTOR_SIZE = 5; 85 86 90 private final static byte USED = 0, 91 DELETED = (byte) 0x080; 92 93 96 private final static boolean SECTORS_CACHED = true; 97 98 99 102 private DebugLogger debug; 103 104 107 private int sector_size; 108 109 112 private File data_file; 113 114 117 private RandomAccessFile data_store; 118 119 122 private boolean read_only; 123 124 127 private long data_store_size; 128 129 133 private int sector_offset; 134 135 139 private byte[] sector_buffer; 140 141 144 private int buffered_sector; 145 146 149 private int delete_head; 150 151 154 private int used_sector_count; 155 156 161 private int lock_count; 162 163 166 private Cache sector_cache; 167 168 169 175 public FixedSizeDataStore(File data_file, int sector_size, 176 boolean cache_access, 177 DebugLogger logger) { 178 this.debug = logger; 179 180 if (cache_access) { 182 sector_cache = new Cache(64); 183 } 184 else { 185 sector_cache = null; 186 } 187 188 if (sector_size > 0) { 189 this.sector_size = sector_size + EXTRA_SECTOR_SIZE; 190 } 191 else { 192 this.sector_size = -1; 193 } 194 this.data_file = data_file; 195 } 196 197 public FixedSizeDataStore(File data_file, int sector_size, 198 DebugLogger logger) { 199 this(data_file, sector_size, SECTORS_CACHED, logger); 200 } 201 202 204 207 boolean locked() { 208 return (lock_count > 0); 209 } 210 211 214 private int sectorCount() throws IOException { 215 return (int) ((data_store_size - sector_offset) / sector_size); 219 } 220 221 224 private long seekSector(int sector) throws IOException { 225 long ra_index = (sector * sector_size); 226 long seek_to = ra_index + sector_offset; 227 data_store.seek(seek_to); return seek_to; 229 } 230 231 235 private void readSector(int sector) throws IOException { 236 237 if (buffered_sector != sector) { 239 240 if (sector_cache != null) { 241 Integer cacheKey = new Integer (sector); 243 byte[] sbuf = (byte[]) sector_cache.get(cacheKey); 244 if (sbuf == null) { 245 seekSector(sector); 247 data_store.readFully(sector_buffer, 0, sector_size); 248 sbuf = new byte[sector_size]; 249 System.arraycopy(sector_buffer, 0, sbuf, 0, sector_size); 250 sector_cache.put(cacheKey, sbuf); 251 } 252 else { 253 System.arraycopy(sbuf, 0, sector_buffer, 0, sector_size); 255 } 256 } 257 else { 258 seekSector(sector); 260 data_store.readFully(sector_buffer, 0, sector_size); 261 } 262 263 buffered_sector = sector; 264 } 265 } 266 267 271 private void setDataStoreSize(long new_size) throws IOException { 272 long p = new_size - 1; 273 if (p > 0) { 274 data_store.seek(p); 275 data_store.write(0); 276 data_store_size = new_size; 277 } 278 } 279 280 284 private void writeSector(int sector, int length) throws IOException { 285 long seek_to = seekSector(sector); 286 if (seek_to == data_store_size) { 288 setDataStoreSize(seek_to + sector_size); 291 seekSector(sector); 292 } 293 if (length <= sector_size) { 295 data_store.write(sector_buffer, 0, length); 296 if (sector_cache != null) { 297 byte[] sbuf = new byte[sector_size]; 299 System.arraycopy(sector_buffer, 0, sbuf, 0, length); 300 sector_cache.put(new Integer (sector), sbuf); 301 } 302 } 303 else { 304 throw new IOException("length > sector_size"); 305 } 306 } 307 308 312 private void writeSector(int sector) throws IOException { 313 writeSector(sector, sector_size); 314 } 315 316 319 private void setSectorHeader(byte status, int next_sector) 320 throws IOException { 321 sector_buffer[0] = status; 322 sector_buffer[1] = (byte) ((next_sector >>> 24) & 0xFF); 323 sector_buffer[2] = (byte) ((next_sector >>> 16) & 0xFF); 324 sector_buffer[3] = (byte) ((next_sector >>> 8) & 0xFF); 325 sector_buffer[4] = (byte) ((next_sector >>> 0) & 0xFF); 326 } 327 328 334 private int writeBufToSector(int sector, int next_sector, 335 byte[] buf, int offset, int length) throws IOException { 336 337 setSectorHeader(USED, next_sector); 339 340 System.arraycopy(buf, offset, sector_buffer, 5, length); 341 342 347 ++used_sector_count; 349 synch(); 351 writeSector(sector, length + 5); 353 buffered_sector = sector; 355 356 return sector; 358 } 359 360 363 private int reclaimTopFree() throws IOException { 364 int free_sector = delete_head; 366 readSector(free_sector); 368 369 int c1 = (((int) sector_buffer[1]) & 0x0FF); 370 int c2 = (((int) sector_buffer[2]) & 0x0FF); 371 int c3 = (((int) sector_buffer[3]) & 0x0FF); 372 int c4 = (((int) sector_buffer[4]) & 0x0FF); 373 374 delete_head = (c1 << 24) + (c2 << 16) + (c3 << 8) + (c4); 375 return free_sector; 376 } 377 378 386 private int findFreeSector() throws IOException { 387 if (!locked() && delete_head != -1) { 389 return reclaimTopFree(); 390 } 391 392 return sectorCount(); 395 396 } 397 398 403 private int findFreeSectorPastNext() throws IOException { 404 if (!locked() && delete_head != -1) { 406 return reclaimTopFree(); 407 } 408 409 return sectorCount() + 1; 412 } 413 414 422 private int[] findFreeSectors(int count) throws IOException { 423 int fs_index = 0; 424 int[] free_sectors = new int[count]; 425 if (!locked()) { 427 while (fs_index < count && delete_head != -1) { 428 free_sectors[fs_index] = reclaimTopFree(); 429 ++fs_index; 430 } 431 } 432 int sec_count = sectorCount(); 433 while (fs_index < count) { 435 free_sectors[fs_index] = sec_count; 436 ++sec_count; 437 ++fs_index; 438 } 439 return free_sectors; 441 } 442 443 444 445 447 451 public long totalSize() { 452 return data_file.length(); 453 } 454 455 460 public void writeReservedBuffer(byte[] info, int offset, int length, 461 int res_offset) throws IOException { 462 if ((length + res_offset) > 128) { 463 throw new Error ("Attempted to write > 128 bytes in reserve buffer."); 464 } 465 data_store.seek(res_offset + 64); 466 data_store.write(info, offset, length); 467 } 468 469 public void writeReservedBuffer(byte[] info, int offset, int length) 470 throws IOException { 471 writeReservedBuffer(info, offset, length, 0); 472 } 473 474 477 public void readReservedBuffer(byte[] info, int offset, int length) 478 throws IOException { 479 if (length > 128) { 480 throw new Error ("Attempted to read > 128 bytes from reserve buffer."); 481 } 482 data_store.seek(64); 483 data_store.readFully(info, offset, length); 484 } 485 486 private byte[] sync_buffer = new byte[16]; 489 490 495 public void synch() throws IOException { 496 if (!read_only) { 497 ByteArrayUtil.setLong(delete_head, sync_buffer, 0); 499 ByteArrayUtil.setLong(used_sector_count, sync_buffer, 8); 501 502 data_store.seek(12); 505 data_store.write(sync_buffer, 0, 16); 506 } 507 } 508 509 514 public void hardSynch() throws IOException { 515 if (!read_only) { 516 synch(); 517 try { 519 data_store.getFD().sync(); 520 } 521 catch (SyncFailedException e) { } 522 } 523 } 524 525 528 public boolean isReadOnly() { 529 return read_only; 530 } 531 532 542 public boolean open(boolean read_only) throws IOException { 543 this.read_only = read_only; 544 545 if (!data_file.exists()) { 547 if (sector_size <= 0) { 548 throw new IOException("Sector size not set for new file."); 549 } 550 } 551 552 String mode = read_only ? "r" : "rw"; 554 data_store = new RandomAccessFile(data_file, mode); 555 data_store.seek(0); 556 if (data_store.length() < SECTOR_DATA_OFFSET) { 558 if (read_only) { 559 throw new IOException( 560 "Unable to open FixedSizeDataStore. No header found."); 561 } 562 563 ByteArrayOutputStream bout = 564 new ByteArrayOutputStream(SECTOR_DATA_OFFSET); 565 DataOutputStream dout = new DataOutputStream(bout); 566 567 dout.writeInt(MAGIC); 570 dout.writeInt(0x0100); 572 dout.writeInt(sector_size); 574 dout.writeLong(-1); 576 dout.writeLong(0); 578 dout.writeByte(0); 580 dout.writeInt(SECTOR_DATA_OFFSET); 582 583 byte[] buf = bout.toByteArray(); 585 dout.close(); 586 byte[] buf2 = new byte[SECTOR_DATA_OFFSET]; 587 System.arraycopy(buf, 0, buf2, 0, buf.length); 588 for (int i = buf.length; i < SECTOR_DATA_OFFSET; ++i) { 589 buf2[i] = (byte) 255; 590 } 591 data_store.write(buf2); 592 593 } 594 data_store.seek(0); 595 data_store_size = data_store.length(); 597 598 if (data_store.readInt() == MAGIC) { 600 int version = data_store.readInt(); 602 if (version != 0x0100) { 603 throw new IOException("Unknown version."); 604 } 605 int ss_check = data_store.readInt(); 607 if (sector_size <= 0) { 609 sector_size = ss_check; 610 } 611 if (ss_check == sector_size) { 612 613 boolean need_repair = false; 614 615 delete_head = (int) data_store.readLong(); 617 used_sector_count = (int) data_store.readLong(); 619 need_repair = data_store.readByte() == 0 ? false : true; 621 sector_offset = data_store.readInt(); 623 624 sector_buffer = new byte[sector_size]; 625 buffered_sector = -2; 626 627 if (!read_only) { 630 data_store.seek(28); 631 data_store.writeByte(1); 632 } 633 634 int pred_size = (sectorCount() * sector_size) + sector_offset; 637 643 if (pred_size != data_store_size) { 644 debug.write(Lvl.ERROR, this, 645 "The FixedSizeDataStore file size is incorrect."); 646 debug.write(Lvl.ERROR, this, 647 "File size should be: " + pred_size + "\n" + 648 "But it's really: " + data_store_size); 649 need_repair = true; 650 } 651 652 data_store.seek(sector_offset); 654 655 if (need_repair) { 657 debug.write(Lvl.ALERT, this, "Store not closed cleanly."); 658 } 659 660 return need_repair; 662 663 } 664 else { 665 throw new IOException( 666 "Sector size for this data store does not match."); 667 } 668 } 669 else { 670 throw new IOException("Format invalid; MAGIC number didn't match."); 671 } 672 673 } 674 675 678 public void close() throws IOException { 679 synch(); 681 if (!read_only) { 685 data_store.seek(28); 686 data_store.writeByte(0); 687 } 688 long close_size = data_store.length(); 690 if (close_size != data_store_size) { 691 debug.write(Lvl.ERROR, this, 692 "On closing file, data_store_size != close_size (" + 693 data_store_size + " != " + close_size + ")"); 694 } 695 696 try { 698 data_store.getFD().sync(); 699 } 700 catch (SyncFailedException e) { } 701 702 data_store.close(); 704 data_store = null; 706 sector_buffer = null; 707 buffered_sector = -2; 708 709 } 710 711 714 public boolean isClosed() { 715 return data_store == null; 716 } 717 718 721 public void delete() { 722 if (data_store == null) { 723 data_file.delete(); 724 } 725 else { 726 throw new Error ("Must close before FixedSizeDataStore is deleted."); 727 } 728 } 729 730 731 732 733 736 public boolean exists() throws IOException { 737 return data_file.exists(); 738 } 739 740 744 public int getSectorSize() { 745 return sector_size - EXTRA_SECTOR_SIZE; 746 } 747 748 752 public int getSectorUseCount() { 753 return used_sector_count; 754 } 755 756 760 public int rawSectorCount() throws IOException { 761 return sectorCount(); 762 } 763 764 765 767 773 public void lock() { 774 ++lock_count; 775 } 776 777 780 public void unlock() { 781 --lock_count; 782 if (lock_count < 0) { 783 throw new Error ("Unlocked more times than we locked."); 784 } 785 } 786 787 788 790 794 public boolean isSectorDeleted(int sector) throws IOException { 795 readSector(sector); 796 return ((sector_buffer[0] & DELETED) != 0); 797 } 798 799 801 804 public byte[] getSector(int sector, byte[] buf, 805 int offset, int length) throws IOException { 806 if (sector >= sectorCount()) { 807 throw new IOException("Can't get sector, out of range."); 808 } 809 810 int ssize = getSectorSize(); 811 if (length > ssize) { 812 throw new IOException("length > sector size"); 813 } 814 readSector(sector); 815 System.arraycopy(sector_buffer, EXTRA_SECTOR_SIZE, buf, offset, length); 816 return buf; 817 } 818 819 822 public byte[] getSector(int sector, byte[] buf) throws IOException { 823 return getSector(sector, buf, 0, 824 Math.min(buf.length, getSectorSize())); 825 } 826 827 830 public byte[] getSector(int sector) throws IOException { 831 if (sector >= sectorCount()) { 832 throw new IOException("Can't get sector, out of range."); 833 } 834 835 int ssize = getSectorSize(); 836 byte[] buf = new byte[ssize]; 837 readSector(sector); 838 System.arraycopy(sector_buffer, EXTRA_SECTOR_SIZE, buf, 0, ssize); 839 return buf; 840 } 841 842 847 public int[] getSectorAsIntArray(int sector, int[] buf) throws IOException { 848 if (sector >= sectorCount()) { 849 throw new IOException("Can't get sector, out of range."); 850 } 851 852 int length = buf.length * 4; 853 int ssize = getSectorSize(); 854 if (length > ssize) { 855 throw new IOException("length > sector size"); 856 } 857 readSector(sector); 858 859 int p = EXTRA_SECTOR_SIZE; 861 int i = 0; 862 while (i < buf.length) { 863 864 int c1 = (((int) sector_buffer[p++]) & 0x0FF); 865 int c2 = (((int) sector_buffer[p++]) & 0x0FF); 866 int c3 = (((int) sector_buffer[p++]) & 0x0FF); 867 int c4 = (((int) sector_buffer[p++]) & 0x0FF); 868 int v = (c1 << 24) + (c2 << 16) + (c3 << 8) + (c4); 869 870 buf[i++] = v; 871 } 872 873 return buf; 874 875 } 876 877 878 879 884 public int readAcross(int sector_head, byte[] buf, int offset, int length) 885 throws IOException { 886 if (sector_head >= sectorCount()) { 887 throw new IOException("Can't get sector, out of range."); 888 } 889 890 int to_read = length; 891 int ssize = getSectorSize(); 892 893 int walk = sector_head; 894 895 while (walk != -1 && to_read > 0) { 896 897 readSector(walk); 899 if ((sector_buffer[0] & DELETED) != 0) { 901 throw new IOException("Can not read across a deleted chain."); 902 } 903 int next_walk = ByteArrayUtil.getInt(sector_buffer, 1); 905 906 int amount_read = Math.min(to_read, ssize); 908 System.arraycopy(sector_buffer, EXTRA_SECTOR_SIZE, buf, offset, 909 amount_read); 910 911 offset += amount_read; 912 to_read -= amount_read; 913 914 walk = next_walk; 916 917 } 918 919 return offset; 920 921 } 922 923 928 public int[] getSectorChain(int sector_head, int length) throws IOException { 929 930 if (sector_head >= sectorCount()) { 931 throw new IOException("Can't get sector, out of range."); 932 } 933 934 int span_count = calculateSectorSpan(length); 936 937 int[] spans = new int[span_count]; 938 939 int ssize = getSectorSize(); 940 int walk = sector_head; 941 int chain_count = 0; 942 943 while (chain_count < span_count) { 944 945 spans[chain_count] = walk; 946 947 readSector(walk); 949 walk = ByteArrayUtil.getInt(sector_buffer, 1); 951 952 ++chain_count; 954 955 } 956 957 return spans; 958 959 } 960 961 966 public int[] getSectorChain(int sector_head) throws IOException { 967 968 if (sector_head >= sectorCount()) { 969 throw new IOException("Can't get sector, out of range."); 970 } 971 972 IntegerVector spans = new IntegerVector(); 973 974 int ssize = getSectorSize(); 975 int walk = sector_head; 976 977 while (walk > -1) { 978 spans.addInt(walk); 979 readSector(walk); 981 walk = ByteArrayUtil.getInt(sector_buffer, 1); 983 } 984 985 return spans.toIntArray(); 986 987 } 988 989 991 1000 public void deleteSector(int sector) throws IOException { 1001 deleteAcross(sector); 1002 } 1003 1004 1009 public void deleteAcross(final int sector_head) throws IOException { 1010 1011 if (sector_head < 0) { 1012 throw new IOException("Sector is out of range."); 1013 } 1014 1015 if (sector_head >= sectorCount()) { 1016 throw new IOException("Can't get sector, out of range."); 1017 } 1018 1019 1027 int walk = sector_head; 1028 1029 while (walk != -1) { 1030 1031 readSector(walk); 1033 if ((sector_buffer[0] & DELETED) != 0) { 1034 throw new IOException("Sector has already been deleted."); 1036 } 1037 1038 int next_walk = ByteArrayUtil.getInt(sector_buffer, 1); 1040 1041 sector_buffer[0] = DELETED; 1043 if (next_walk == -1) { 1045 ByteArrayUtil.setInt(delete_head, sector_buffer, 1); 1046 } 1047 seekSector(walk); 1049 data_store.write(sector_buffer, 0, 5); 1050 if (sector_cache != null) { 1051 sector_cache.remove(new Integer (walk)); 1053 } 1054 --used_sector_count; 1056 1057 walk = next_walk; 1059 1060 } 1061 1062 delete_head = sector_head; 1064 synch(); 1066 1067 } 1068 1069 1072 public void deleteAllSectors() throws IOException { 1073 int sector_count = sectorCount(); 1074 for (int i = 0; i < sector_count; ++i) { 1075 readSector(i); 1076 sector_buffer[0] = DELETED; 1077 int next = i + 1; 1078 if (i == sector_count - 1) { 1079 next = -1; 1080 } 1081 ByteArrayUtil.setInt(next, sector_buffer, 1); 1082 writeSector(i); 1083 } 1084 delete_head = sector_count == 0 ? -1 : 0; 1086 used_sector_count = 0; 1088 synch(); 1090 } 1091 1092 1094 1099 public int overwriteSector(int sector, byte[] buf, int offset, int length) 1100 throws IOException { 1101 int ssize = getSectorSize(); 1102 if (length > ssize) { 1103 throw new IOException("Sector too large to add to store."); 1104 } 1105 1106 return writeBufToSector(sector, -1, buf, offset, length); 1108 1109 } 1110 1111 1116 public int overwriteSector(int sector, byte[] buf) throws IOException { 1117 return overwriteSector(sector, buf, 0, buf.length); 1118 } 1119 1120 1125 public int addSector(byte[] buf, int offset, int length) throws IOException { 1126 int ssize = getSectorSize(); 1127 if (length > ssize) { 1128 throw new IOException("Sector too large to add to store."); 1129 } 1130 int sector = findFreeSector(); 1132 1133 return writeBufToSector(sector, -1, buf, offset, length); 1135 1136 } 1137 1138 1143 public int addSector(byte[] buf) throws IOException { 1144 return addSector(buf, 0, buf.length); 1145 } 1146 1147 1150 public int calculateSectorSpan(int length) { 1151 int sector_size = getSectorSize(); 1152 int span_count = length / sector_size; 1153 if (length == 0 || (length % sector_size) != 0) { 1155 ++span_count; 1156 } 1157 return span_count; 1158 } 1159 1160 1165 public int writeAcross(byte[] buf, int offset, int length) 1166 throws IOException { 1167 1168 int sector_size = getSectorSize(); 1169 1170 int span_count = calculateSectorSpan(length); 1172 1173 int[] free_sectors = findFreeSectors(span_count); 1175 Arrays.sort(free_sectors, 0, span_count); 1177 1178 int to_write = length; 1180 int to_offset = 0; 1181 1182 for (int i = 0; i < span_count; ++i) { 1183 int sector = free_sectors[i]; 1184 int next_sector; 1185 if (i < span_count - 1) { 1186 next_sector = free_sectors[i + 1]; 1187 } 1188 else { 1189 next_sector = -1; 1190 } 1191 1192 writeBufToSector(sector, next_sector, buf, to_offset, 1194 Math.min(to_write, sector_size)); 1195 1196 to_write -= sector_size; 1197 to_offset += sector_size; 1198 } 1199 1200 return free_sectors[0]; 1202 1203 } 1204 1205 1206 1209 private SectorOutputStream sector_output_stream; 1210 1211 1223 public OutputStream getSectorOutputStream() throws IOException { 1224 sector_output_stream = new SectorOutputStream(); 1225 return sector_output_stream; 1226 } 1227 1228 1232 public int getSectorOfLastOutputStream() { 1233 return sector_output_stream.first_sector; 1234 } 1235 1236 1240 public int getLengthOfLastOutputStream() { 1241 return sector_output_stream.count; 1242 } 1243 1244 1248 public void wipeLastOutputStream() { 1249 sector_output_stream = null; 1250 } 1251 1252 1263 public InputStream getSectorInputStream(int sector_head) throws IOException { 1264 return new SectorInputStream(sector_head); 1265 } 1266 1267 1269 1281 public void copyTo(File path) throws IOException { 1282 String fname = data_file.getName(); 1283 1284 FileOutputStream fout = new FileOutputStream(new File(path, fname)); 1285 int BUF_SIZE = 65536; byte[] buf = new byte[BUF_SIZE]; 1287 1288 data_store.seek(0); 1289 int read = data_store.read(buf, 0, BUF_SIZE); 1290 while (read >= 0) { 1291 fout.write(buf, 0, read); 1292 read = data_store.read(buf, 0, BUF_SIZE); 1293 } 1294 1295 fout.close(); 1296 1297 } 1298 1299 1306 public void fix(UserTerminal terminal) throws IOException { 1307 1308 terminal.println("- File: " + data_file); 1309 1310 synch(); 1312 1313 if ((data_store_size - (long) sector_offset) % 1315 (long) sector_size != 0) { 1316 terminal.println("+ Altering length of file so it is correct " + 1317 "for sector size"); 1318 int row_count = sectorCount() + 1; 1319 long new_size = (row_count * sector_size) + sector_offset; 1320 setDataStoreSize(new_size); 1321 } 1322 1323 IntegerVector sector_info = new IntegerVector(); 1324 IntegerVector scc = new IntegerVector(); 1325 int null_count = 0; 1326 1327 int sector_count = sectorCount(); 1329 terminal.println("- Sector Count: " + sectorCount()); 1330 1331 for (int i = 0; i < sector_count; ++i) { 1333 readSector(i); 1334 int next_chain = ByteArrayUtil.getInt(sector_buffer, 1); 1336 sector_info.addInt((int) sector_buffer[0]); 1337 sector_info.addInt(next_chain); 1338 1339 if (next_chain == -1) { 1340 ++null_count; 1341 } 1342 else { 1343 int old_val = 0; 1344 if (next_chain < scc.size()) { 1345 old_val = scc.intAt(next_chain); 1346 } 1347 scc.placeIntAt(old_val + 1, next_chain); 1348 } 1349 } 1350 1351 terminal.println("- unchained sectors = " + null_count); 1353 IntegerVector bad_sectors = new IntegerVector(); 1356 for (int i = 0; i < scc.size(); ++i) { 1357 int ref_count = scc.intAt(i); 1358 if (ref_count > 1) { 1359 terminal.println("- [" + i + "] reference count = " + ref_count); 1360 terminal.println("+ Marking all references as bad (except first)."); 1361 boolean found_first = false; 1362 for (int n = 0; n < sector_info.size(); n += 2) { 1363 if (sector_info.intAt(n + 1) == i) { 1364 if (found_first) { 1365 bad_sectors.addInt(n / 2); 1366 } 1367 found_first = true; 1368 } 1369 } 1370 } 1371 } 1372 1373 if (bad_sectors.size() > 0) { 1375 terminal.println("+ Marked " + bad_sectors.size() + " sectors bad."); 1376 } 1377 1378 for (int i = 0; i < bad_sectors.size(); ++i) { 1380 int sector = bad_sectors.intAt(i); 1381 readSector(sector); 1382 sector_buffer[0] = DELETED; 1383 writeSector(sector); 1384 } 1385 1386 1389 1390 repair(); 1392 1393 } 1394 1395 1407 public boolean clearDeletedSectors() throws IOException { 1408 1409 if (locked()) { 1410 throw new IOException( 1411 "Store is locked, can not reclaim deleted sectors."); 1412 } 1413 1414 if (delete_head != -1) { 1416 1417 int scount = sectorCount(); 1420 int move_to = 0; 1421 int row_count = 0; 1422 for (int i = 0; i < scount; ++i) { 1423 readSector(i); 1425 if ((sector_buffer[0] & DELETED) == 0) { 1427 ++row_count; 1428 if (move_to < i) { 1430 writeSector(move_to); 1432 buffered_sector = move_to; 1433 } 1434 move_to = move_to + 1; 1435 } 1436 } 1437 1438 long new_size = (row_count * sector_size) + sector_offset; 1440 setDataStoreSize(new_size); 1441 delete_head = -1; 1443 used_sector_count = row_count; 1445 synch(); 1447 return true; 1449 1450 } 1451 else { 1452 return false; 1454 } 1455 } 1456 1457 1465 1482 public void repair() throws IOException { 1483 1484 delete_head = -1; 1486 int scount = sectorCount(); 1487 int row_count = 0; 1488 int delete_count = 0; 1489 1490 byte[] mark_buffer = new byte[5]; 1491 1492 for (int i = 0; i < scount; ++i) { 1493 readSector(i); 1495 if ((sector_buffer[0] & DELETED) != 0) { 1497 int v = delete_head; 1499 mark_buffer[0] = DELETED; 1500 mark_buffer[1] = (byte) ((v >>> 24) & 0xFF); 1501 mark_buffer[2] = (byte) ((v >>> 16) & 0xFF); 1502 mark_buffer[3] = (byte) ((v >>> 8) & 0xFF); 1503 mark_buffer[4] = (byte) ((v >>> 0) & 0xFF); 1504 seekSector(i); 1505 data_store.write(mark_buffer, 0, 5); 1506 if (sector_cache != null) { 1507 sector_cache.remove(new Integer (i)); 1509 } 1510 delete_head = i; 1511 1512 ++delete_count; 1513 } 1514 else { 1515 ++row_count; 1517 } 1518 } 1519 1520 used_sector_count = row_count; 1523 synch(); 1525 1526 debug.write(Lvl.MESSAGE, this, 1527 "Repair found (" + delete_count + ") deleted, (" + 1528 row_count + ") used sectors."); 1529 } 1530 1531 1533 1536 public String statusString() throws IOException { 1537 int sc = sectorCount(); 1538 1539 StringBuffer str = new StringBuffer (); 1540 str.append("Sector Count: "); 1541 str.append(sc); 1542 str.append("\nSectors Used: "); 1543 str.append(getSectorUseCount()); 1544 str.append("\nLocks: "); 1545 str.append(lock_count); 1546 str.append("\nFree Sectors: "); 1547 str.append(sc - getSectorUseCount()); 1548 str.append("\n"); 1549 1550 return new String (str); 1551 } 1552 1553 1555 1559 private class SectorOutputStream extends OutputStream { 1560 1561 1564 private final byte[] buf; 1565 1566 1569 private int first_sector = -1; 1570 1571 1574 private int cur_sector = -1; 1575 1576 1579 private int last_sector = -1; 1580 1581 1584 private int index; 1585 1586 1589 private int count; 1590 1591 SectorOutputStream() throws IOException { 1592 buf = new byte[getSectorSize()]; 1593 index = 0; 1594 count = 0; 1595 first_sector = findFreeSector(); 1596 cur_sector = first_sector; 1597 } 1598 1599 1601 public void write(int b) throws IOException { 1602 if (index >= buf.length) { 1603 1605 int next_sector = findFreeSector(); 1606 if (next_sector == cur_sector) { 1607 next_sector = next_sector + 1; 1610 } 1611 1612 writeBufToSector(cur_sector, next_sector, buf, 0, index); 1614 cur_sector = next_sector; 1615 index = 0; 1616 } 1617 1618 buf[index] = (byte) b; 1619 ++index; 1620 ++count; 1621 1622 } 1623 1624 public void write(byte[] b, int offset, int len) throws IOException { 1625 while (index + len > buf.length) { 1626 int to_copy = buf.length - index; 1628 System.arraycopy(b, offset, buf, index, to_copy); 1629 offset += to_copy; 1630 len -= to_copy; 1631 index += to_copy; count += to_copy; 1633 1634 int next_sector = findFreeSector(); 1635 if (next_sector == cur_sector) { 1636 next_sector = next_sector + 1; 1639 } 1640 writeBufToSector(cur_sector, next_sector, buf, 0, index); 1641 cur_sector = next_sector; 1642 1643 index = 0; 1644 } 1645 1646 if (len > 0) { 1647 System.arraycopy(b, offset, buf, index, len); 1648 index += len; 1649 count += len; 1650 } 1651 1652 } 1653 1654 public void flush() throws IOException { 1655 } 1657 1658 public void close() throws IOException { 1659 writeBufToSector(cur_sector, -1, buf, 0, index); 1660 } 1661 1662 } 1663 1664 1668 private final class SectorInputStream extends InputStream { 1669 1670 1673 private int sector; 1674 1675 1678 private int index; 1679 1680 1683 private int count; 1684 1685 1688 private byte[] sector_buffer; 1689 1690 1691 1694 SectorInputStream(int sector_head) throws IOException { 1695 this.sector = sector_head; 1696 this.sector_buffer = FixedSizeDataStore.this.sector_buffer; 1697 1698 loadNextSector(); 1700 1701 count = 0; 1702 } 1703 1704 1708 private void loadNextSector() throws IOException { 1709 if (sector != -1) { 1710 readSector(sector); 1712 } 1713 index = EXTRA_SECTOR_SIZE; 1714 sector = ByteArrayUtil.getInt(sector_buffer, 1); 1716 } 1717 1718 1720 public final int read() throws IOException { 1721 1722 int b = ((int) sector_buffer[index]) & 0x0FF; 1723 ++index; 1724 ++count; 1725 if (index >= sector_size) { 1726 loadNextSector(); 1727 } 1728 return b; 1729 1730 } 1731 1732 public int read(byte[] b, int offset, int len) throws IOException { 1733 int original_len = len; 1734 1735 while (index + len > sector_size) { 1736 int to_copy = sector_size - index; 1738 System.arraycopy(sector_buffer, index, b, offset, to_copy); 1739 offset += to_copy; 1740 len -= to_copy; 1741 index += to_copy; count += to_copy; 1743 1744 loadNextSector(); 1746 1747 } 1748 1749 if (len > 0) { 1750 System.arraycopy(sector_buffer, index, b, offset, len); 1751 index += len; 1752 count += len; 1753 1754 if (index >= sector_size) { 1755 loadNextSector(); 1756 } 1757 1758 } 1759 1760 return original_len; 1761 } 1762 1763 public long skip(long len) throws IOException { 1764 long original_len = len; 1765 1766 while (index + len > sector_size) { 1767 int to_copy = sector_size - index; 1768 len -= to_copy; 1769 index += to_copy; count += to_copy; 1771 1772 loadNextSector(); 1774 1775 } 1776 1777 if (len > 0) { 1778 index += len; 1779 count += len; 1780 1781 if (index >= sector_size) { 1782 loadNextSector(); 1783 } 1784 1785 } 1786 1787 return original_len; 1788 } 1789 1790 } 1791 1792} 1793 | Popular Tags |