|                                                                                                              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                                                                                                                                                                                              |