1 19 package org.netbeans.mdr.persistence.btreeimpl.btreestorage; 20 21 import java.io.*; 22 import java.text.*; 23 import java.util.*; 24 25 import org.netbeans.mdr.persistence.btreeimpl.btreeindex.*; 26 import org.netbeans.mdr.persistence.*; 27 import org.netbeans.mdr.util.Logger; 28 29 72 73 public class BtreeDatabase implements 74 SinglevaluedIndex, MDRCache.OverflowHandler { 75 76 77 static final int PAGE_SIZE = 2048; 78 static final int FILE_CACHE_SIZE = 128; 79 static final int MDR_CACHE_SIZE = 1024; 80 static final int MDR_CACHE_THRESHHOLD = 1000; 81 82 83 private int modificationLevel; 84 85 86 private final String repositoryName; 87 88 89 private BtreeDataFile dataFile; 90 91 92 private SinglevaluedIndex indexFile; 93 94 95 private FileCache fileCache; 96 97 98 private MDRCache cache; 99 100 101 private CounterIndex classIndex; 102 103 104 private boolean classIndexChanged; 105 106 107 private static String CLASS_INDEX_TYPE = 108 "org.netbeans.mdr.persistence.btreeimpl.btreestorage.CounterIndex"; 109 110 111 private ArrayList classes; 112 113 114 private MofidIndex indexIndex; 115 116 117 private BtreeStorage myStorage; 118 119 120 private boolean saveFailed = false; 121 122 123 private byte [] baoStrmToBytes; 124 125 126 private ByteArrayOutputStream baoStrm = new ByteArrayOutputStream(); 127 private DataOutputStream daoStrm = new DataOutputStream(baoStrm); 128 129 private TransactionCache transactionCache = null; 130 131 134 private PrintStream loggingStream; 135 136 141 BtreeDatabase(String name, BtreeStorage parent, boolean isNew) throws StorageException { 142 repositoryName = name; 143 myStorage = parent; 144 classes = new ArrayList(); 145 try { 146 classes.add(Class.forName(CLASS_INDEX_TYPE)); 147 } 148 catch (ClassNotFoundException ex) { 149 throw new RuntimeException (ex.getMessage()); 150 } 151 open(isNew); 152 } 153 154 static final int DFL = 0; 155 static final int IFL = 1; 156 static final int LFL = 2; 157 private static final String [] SUFFIXES = {".btd", ".btx", ".btb"}; 158 159 160 private static String [] getFileNames(String base) { 161 String names[] = new String [] {getFileName(base, 0), getFileName(base, 1), getFileName(base, 2)}; 162 return names; 163 } 164 165 static String getFileName(String base, int type) { 166 return base.concat(SUFFIXES[type]); 167 } 168 169 170 static boolean exists(String base) { 171 String names[] = getFileNames(base); 172 173 return 174 (new File(names[DFL])).exists() || 175 (new File(names[IFL])).exists() || 176 (new File(names[LFL])).exists(); 177 } 178 179 183 static boolean delete(String base) { 184 String names[] = getFileNames(base); 185 return 186 deleteFile(names[DFL]) & 187 deleteFile(names[IFL]) & 188 deleteFile(names[LFL]); 189 } 190 191 192 private static boolean deleteFile(String name) { 193 File file = new File(name); 194 if (!file.exists()) 195 return true; 196 else 197 return file.delete(); 198 } 199 200 201 static void rename(String from, String to) throws StorageException { 202 if (exists(to)) { 203 throw new StorageBadRequestException( 204 MessageFormat.format("Btree repository {0} already exists", 205 new Object [] {to} )); 206 } 207 208 String fromNames[] = getFileNames(from); 209 String toNames[] = getFileNames(to); 210 boolean success = 211 (new File(fromNames[DFL])).renameTo(new File(toNames[DFL])); 212 if (success) { 213 success = 214 (new File(fromNames[IFL])).renameTo(new File(toNames[IFL])); 215 } 216 if (success) { 217 File fromLog = new File(fromNames[LFL]); 218 if (fromLog.exists()) 219 success = fromLog.renameTo(new File(toNames[DFL])); 220 } 221 if (!success) { 222 throw new StorageBadRequestException( 223 MessageFormat.format( 224 "Unable to rename btree repository {0} to {1}", 225 new Object [] {from, to} ) ); 226 } 227 } 228 229 private int getIntProperty(String propertyName, int defaultValue) { 230 String value = (String ) myStorage.getProperty(propertyName); 231 int result = defaultValue; 232 if (value != null) { 233 try { 234 result = Integer.parseInt(value); 235 } catch (NumberFormatException e) { 236 Logger.getDefault().log("Error getting value of " + propertyName + " storage property: " + e.getMessage()); 237 } 238 } 239 return result; 240 } 241 242 private void open(boolean isNew) throws StorageException { 244 boolean rebuildIndex = false; 245 246 cache = new MDRCache(getIntProperty(BtreeFactory.CACHE_SIZE, MDR_CACHE_SIZE), this, getIntProperty(BtreeFactory.CACHE_THRESHHOLD, MDR_CACHE_THRESHHOLD), (Map) myStorage.getProperty(BtreeFactory.CACHE_INSTANCE)); 247 transactionCache = new TransactionCache (); 248 String names[] = getFileNames(repositoryName); 249 250 String fileNames[] = {names[DFL], names[IFL]}; 251 if (isNew) { 252 FileHeader hdr = 253 FileHeader.createFiles(new String [] {names[IFL]}, 254 PAGE_SIZE, false); 255 BtreeDataFile.create(this.myStorage, names[DFL], hdr, PAGE_SIZE, false); 256 } 257 else { 258 File dfl = new File(names[DFL]); 259 File ifl = new File(names[IFL]); 260 261 if (dfl.exists() && ! ifl.exists()) { 262 263 FileHeader hdr = null; 264 try { 265 RandomAccessFile draf = new RandomAccessFile(dfl, "r"); 266 hdr = new FileHeader(draf); 267 draf.close(); 268 } 269 catch (IOException ex) { 270 throw new StorageIOException(ex); 271 } 272 273 hdr.addFiles(new String [] {names[IFL]}, PAGE_SIZE, false); 274 rebuildIndex = true; 275 } 276 } 277 278 fileCache = new FileCache(fileNames, repositoryName); 279 boolean failure = true; 280 try { 281 dataFile = new BtreeDataFile(this.myStorage, fileCache, 0); 282 myStorage.gen = dataFile; 283 284 indexFile = new PrimaryIndex(repositoryName, 1, fileCache, dataFile.initialMofIdConter(), 285 Storage.EntryType.MOFID, Storage.EntryType.INT); 286 287 if (rebuildIndex) { 288 rebuildIndexFile(); 289 save (true); 290 } 291 292 fetchClassIndex(); 293 294 if (isNew) { 295 save (true); 296 } 297 failure = false; 298 } finally { 299 if (failure) fileCache.abort(); 300 } 301 } 302 303 308 void copy(String target) throws StorageException { 309 FileCache copyCache = null; 310 BtreeDataFile copyFile; 311 312 if (cache.getModStatus() != 0) { 313 throw new StorageBadRequestException( 314 MessageFormat.format( 315 "There are changes to repository {0} that have not been committed", 316 new Object [] {target} )); 317 } 318 319 if (exists(target)) { 320 throw new StorageBadRequestException( 321 MessageFormat.format("Btree repository {0} already exists", 322 new Object [] {target} )); 323 } 324 String copyNames[] = getFileNames(target); 325 String fileNames[] = {copyNames[DFL]}; 326 327 BtreeDataFile.create( this.myStorage, copyNames[DFL], new FileHeader(), PAGE_SIZE, false); 328 try { 329 copyCache = new FileCache(fileNames, target); 330 copyFile = new BtreeDataFile(this.myStorage, copyCache, 0); 331 dataFile.copy(copyFile); 332 copyCache.commit(); 333 copyCache.close(); 334 335 BtreeDatabase db = new BtreeDatabase(target, myStorage, false); 337 db.close(); 338 } 339 catch (StorageException ex) { 340 if (copyCache != null) 341 copyCache.close(); 342 delete(target); 343 throw ex; 344 } 345 } 346 347 351 public void compress() throws StorageException { 352 synchronized (myStorage) { 353 if (cache.getModStatus() != 0) { 354 throw new StorageBadRequestException( 355 MessageFormat.format( 356 "There are changes to repository {0} that have not been committed", 357 new Object [] {repositoryName} )); 358 } 359 360 String tempName = "tmp" + (new Random().nextInt()); 361 copy(tempName); 362 closeFiles(); 363 delete(repositoryName); 364 rename(tempName, repositoryName); 365 open(false); 366 } 367 } 368 369 374 private void rebuildIndexFile() throws StorageException { 375 Iterator iter = dataFile.iterator( 376 BtreeDataFile.ITERATE_NORMAL_EXTENTS); 377 while (iter.hasNext()) { 378 NormalBtreeExtent ext = (NormalBtreeExtent)iter.next(); 379 MOFID k = this.myStorage.readMOFIDData (new ByteArrayInputStream (ext.key)); 380 indexFile.add(k, new Integer (ext.myChunkNum)); 381 } 382 } 383 384 387 public int size() { 388 synchronized (myStorage) { 389 return dataFile.size() + cache.numberNew() - cache.numberDeleted(); 390 } 391 } 392 393 396 public String getName() { 397 return repositoryName; 398 }; 399 400 403 public Storage.EntryType getValueType() { 404 return Storage.EntryType.STREAMABLE; 405 } 406 407 410 public Storage.EntryType getKeyType() { 411 return Storage.EntryType.MOFID; 412 } 413 414 416 void close() throws StorageException { 417 synchronized (myStorage) { 418 closeFiles(); 419 cache.shutDown(); 420 cache = null; 421 transactionCache = null; 422 } 423 } 424 425 427 private void closeFiles() throws StorageException { 428 modificationLevel++; 429 fileCache.abort(); 430 fileCache = null; 431 dataFile = null; 432 indexFile = null; 433 } 434 435 437 public void cacheThreshholdReached(MDRCache cach, int size) 438 throws StorageException { 439 saveChanges(); 440 } 441 442 445 public void commitChanges() throws StorageException { 446 synchronized (myStorage) { 447 save(false); 448 449 if (transactionCache.tresholdReached ()) { 450 try { 451 fileCache.commit(); 453 transactionCache.clear (); 454 } catch (StorageException ex) { 455 saveFailed = true; 456 throw(ex); 457 } } else { 459 transactionCache.commit (); 460 } 461 } 462 } 463 464 467 public void shutDown() throws StorageException { 468 synchronized (myStorage) { 469 cache.shutDown(); 470 try { 471 fileCache.close(); 472 } catch (StorageException ex) { 473 saveFailed = true; 474 throw(ex); 475 } } 477 } 478 479 481 public void saveChanges() throws StorageException { 482 synchronized (myStorage) { 483 save(false); 484 } 485 } 486 487 public String toString() { 488 return myStorage.getStorageId(); 489 } 490 491 492 private void save(boolean commit) throws StorageException { 493 MOFID id; 494 Object value; 495 496 if (saveFailed) { 497 throw new StorageBadRequestException( 500 "A save of this repository has failed previously. Allowing this commit to proceed would potentially corrupt persistent data."); 501 } 502 503 try { 504 modificationLevel++; 505 StorageException writeError; 506 classIndexChanged = false; 507 508 int modStatus = cache.getModStatus(); 509 while (modStatus != 0) { 510 if ((modStatus & MDRCache.M_DELETED) != 0) { 512 Iterator delIter = cache.getDeleted().iterator(); 513 while (delIter.hasNext()) { 514 id = (MOFID)delIter.next(); 515 removeRecord(id); 516 transactionCache.addDeleted(id); 517 } 518 } 519 520 if ((modStatus & MDRCache.M_DIRTY) != 0) { 522 Iterator dirtyIter = cache.getDirty().iterator(); 523 while (dirtyIter.hasNext()) { 524 Map.Entry entry = (Map.Entry) dirtyIter.next(); 525 id = (MOFID) entry.getKey(); 526 value = entry.getValue(); 527 writeError = replaceRecord(id, value); 528 if (writeError == null) { 529 transactionCache.addReplaced(id, baoStrmToBytes); 530 } else { 531 throw writeError; 532 } 533 } 534 } 535 536 if ((modStatus & MDRCache.M_NEW) != 0) { 538 Iterator newIter = cache.getNew().iterator(); 539 while (newIter.hasNext()) { 540 Map.Entry entry = (Map.Entry) newIter.next(); 541 id = (MOFID) entry.getKey(); 542 value = entry.getValue(); 543 writeError = addRecord(id, value); 544 if (writeError == null) { 545 transactionCache.addInserted(id, baoStrmToBytes); 546 } else { 547 throw writeError; 548 } 549 } 550 } 551 552 modStatus = cache.getModStatus(); 553 } 554 555 if (classIndexChanged) { 556 writeError = replaceRecord(BtreeFactory.classIndexId, classIndex); 557 transactionCache.addReplaced(BtreeFactory.classIndexId, baoStrmToBytes); 558 if (writeError != null) 559 throw writeError; 560 classIndexChanged = false; 561 } 562 563 if (commit) { 565 fileCache.commit(); 566 transactionCache.clear (); 567 } 568 } 569 catch (StorageException ex) { 570 saveFailed = true; 572 throw(ex); 573 } finally { 574 cache.updateSize(); 575 } 576 } 577 578 580 public void rollbackChanges() throws StorageException { 581 synchronized (myStorage) { 582 modificationLevel++; 583 Integer offset; 584 int dataOffset; 585 586 TransactionCache.CacheIterator iter = transactionCache.iterator (); 588 long counter = dataFile.getMofIdCounter (); 589 boolean dataCommited = transactionCache.containsCommitedData (); 590 591 close(); 593 open(false); 594 595 try { 597 while (iter.hasNext ()) { 598 TransactionCache.Record rec = iter.next (); 599 switch (rec.op) { 600 case TransactionCache.OP_DELETE: 601 removeRecord(rec.id); 602 break; 603 case TransactionCache.OP_REPLACE: 604 offset = (Integer )indexFile.get(rec.id); 605 dataOffset = dataFile.replace( 606 offset.intValue(), rec.id.getSerialNumber(), rec.value); 607 indexFile.replace(rec.id, new Integer (dataOffset)); 608 break; 609 case TransactionCache.OP_INSERT: 610 dataOffset = dataFile.put(rec.id.getSerialNumber(), rec.value); 611 indexFile.add(rec.id, new Integer (dataOffset)); 612 break; 613 } 615 } 617 dataFile.setMofIdCounter (counter); 619 fileCache.commit(); 620 } catch (StorageException ex) { 621 saveFailed = true; 623 throw(ex); 624 } 625 } 626 } 627 628 632 public boolean remove(Object mKey) throws StorageException { 633 synchronized (myStorage) { 634 modificationLevel++; 635 if (!exists((MOFID)mKey)) { 636 return false; 637 } 638 else { 639 cache.remove(mKey); 640 return true; 641 } 642 } 643 } 644 645 649 public void add(Object key, Object value) throws StorageException { 650 MOFID mKey = (MOFID)key; 651 synchronized (myStorage) { 652 modificationLevel++; 653 if (exists(mKey)) { 654 throw new StorageBadRequestException( 655 MessageFormat.format("Record with key {0} already exists", 656 new Object [] {mKey} ) ); 657 } 658 addToCache(mKey, value); 659 } 660 } 661 662 663 private void addToCache(MOFID key, Object value) throws StorageException { 664 cache.put(key, value); 665 cache.setNew(key); 666 } 667 668 675 public void replace(Object key, Object value) throws StorageException { 676 MOFID mKey = (MOFID)key; 677 synchronized (myStorage) { 678 modificationLevel++; 679 if (!exists(mKey)) { 680 noSuchRecord(mKey); 681 } 682 683 replaceInCache(mKey, value); 684 } 685 } 686 687 688 private void replaceInCache(MOFID key, Object value) throws StorageException { 689 boolean isNew = cache.isNew(key); 690 cache.replace(key, value); 691 if (isNew) 692 cache.setNew(key); 693 else 694 cache.setDirty(key); 695 } 696 697 702 public boolean put(Object key, Object value) throws StorageException { 703 synchronized (myStorage) { 704 modificationLevel++; 705 MOFID mKey = (MOFID)key; 706 707 if (!exists(mKey)) { 708 addToCache(mKey, value); 709 return false; 710 } 711 else { 712 replaceInCache(mKey, value); 713 return true; 714 } 715 } 716 } 717 718 723 public Object getIfExists(Object key)throws StorageException { 724 synchronized (myStorage) { 725 Object retval; 726 retval = cache.get(key); 727 if (retval == null) { 728 if (cache.isDeleted(key)) { 729 return null; 730 } 731 retval = getRecord((MOFID)key); 732 if (retval != null) { 733 cache.put(key, retval); 734 } 735 } 736 737 return retval; 738 } 739 } 740 741 742 public Object getObjectIfExists(Object key, SinglevaluedIndex dummy) throws StorageException { 743 return getIfExists(key); 744 } 745 746 751 public Object get(Object key)throws StorageException { 752 Object retval = getIfExists(key); 753 if (retval == null) { 754 noSuchRecord(key); 755 } 756 757 return retval; 758 } 759 760 761 public Object getObject(Object key, SinglevaluedIndex dummy) 762 throws StorageException { 763 return get(key); 764 } 765 766 public Collection queryByKeyPrefix (Object prefix, SinglevaluedIndex repos) { 767 throw new UnsupportedOperationException (); 768 } 769 770 773 private boolean exists(MOFID key) throws StorageException { 774 if (cache.get(key) != null) { 775 return true; 776 } 777 else if (cache.isDeleted(key)) { 778 return false; 779 } 780 else { 781 return indexFile.getIfExists(key) != null; 782 } 783 } 784 785 788 private boolean removeRecord (MOFID mKey) throws StorageException { 789 Integer offset = (Integer )indexFile.getIfExists(mKey); 790 if (offset == null) { 791 noSuchRecord(mKey); 792 } 793 794 indexFile.remove(mKey); 795 dataFile.remove(offset.intValue(), mKey.getSerialNumber()); 796 return true; 797 } 798 799 802 public void objectStateChanged(Object key) throws StorageException { 803 objectStateChanged((MOFID)key); 804 } 805 806 809 public void objectStateChanged(MOFID mKey) throws StorageException { 810 synchronized (myStorage) { 811 modificationLevel++; 812 cache.setDirty(mKey); 813 } 814 } 815 816 819 Object fetchIndex(String name) throws StorageException { 820 fetchIndexIndex(); 821 MOFID indexID = indexIndex.get(name); 822 return (indexID == null) ? null : get(indexID); 823 } 824 825 828 void dropIndex(String name) throws StorageException { 829 modificationLevel++; 830 fetchIndexIndex(); 831 MOFID indexId = indexIndex.get(name); 832 indexIndex.remove(name); 833 objectStateChanged(BtreeFactory.indexIndexId); 834 remove(indexId); 835 } 836 837 840 public String [] listIndexes() throws StorageException { 841 synchronized (myStorage) { 842 fetchIndexIndex(); 843 String retval[] = indexIndex.listNames(); 844 Arrays.sort(retval); 845 return retval; 846 } 847 } 848 849 854 void addIndex(String name, Object index, MOFID mID) throws StorageException { 855 modificationLevel++; 856 add(mID, index); 857 fetchIndexIndex(); 858 indexIndex.add(name, mID); 859 objectStateChanged(BtreeFactory.indexIndexId); 860 } 861 862 863 private static MofidGenerator currentlyStreamingMofidGenerator = null; 864 865 static MofidGenerator getCurrentlyStreamingMofidGenerator() { 866 return currentlyStreamingMofidGenerator; 867 } 868 869 870 private StorageException writeStreamable(Streamable obj) { 871 MofidGenerator previous = currentlyStreamingMofidGenerator; 872 currentlyStreamingMofidGenerator = dataFile; 873 try { 874 baoStrm.reset(); 875 daoStrm.writeInt(getClassCode(obj.getClass())); 876 obj.write(daoStrm); 877 baoStrmToBytes = baoStrm.toByteArray(); 878 } catch (StorageException ex) { 879 return ex; 880 } 881 catch (IOException ioException) { 882 return (StorageException) Logger.getDefault().annotate(new StorageIOException(ioException), ioException); 883 } 884 catch (RuntimeException th) { 885 return (StorageException) Logger.getDefault().annotate(new StorageTransientDataException( 886 th.getClass().getName() + ": " + th.getMessage()), th); 887 } 888 finally { 889 currentlyStreamingMofidGenerator = previous; 890 } 891 return null; 893 } 894 895 private Streamable readStreamable (DataInputStream stream) throws StorageException { 896 int classCode; 897 Streamable data; 898 899 try { 900 classCode = stream.readInt(); 901 } 902 catch (IOException ex) { 903 throw new StorageIOException(ex); 904 } 905 try { 906 Class cls = (Class )classes.get(classCode); 907 data = (Streamable)cls.newInstance(); 908 } catch (Exception ex) { 909 throw new StoragePersistentDataException(ex.getMessage()); 910 } 911 if (data instanceof StorageClient) { 912 ((StorageClient)data).setStorage(myStorage); 913 } 914 data.read(stream); 915 return data; 916 } 917 918 923 private StorageException addRecord(MOFID mKey, Object value) throws StorageException { 924 StorageException ex = writeStreamable((Streamable)value); 925 if (ex != null) 926 return ex; 927 int dataOffset = dataFile.put(mKey.getSerialNumber(), baoStrmToBytes); 928 indexFile.add(mKey, new Integer (dataOffset)); 929 return null; 930 } 931 932 933 int getClassCode(Class cls) throws StorageException{ 934 String className = cls.getName(); 935 fetchClassIndex(); 936 Integer i = classIndex.getIf(className); 937 if (i != null) { 938 return i.intValue(); 939 } 940 else { 941 int code = classIndex.add(className); 942 classes.add(code, cls); 943 classIndexChanged = true; 944 return code; 945 } 946 } 947 948 953 private StorageException replaceRecord(MOFID mKey,Object value)throws StorageException { 954 StorageException ex = writeStreamable((Streamable)value); 955 if (ex != null) 956 return ex; 957 Integer offset = (Integer )indexFile.get(mKey); 958 int dataOffset = dataFile.replace( 959 offset.intValue(), mKey.getSerialNumber(), baoStrmToBytes); 960 indexFile.replace(mKey, new Integer (dataOffset)); 961 return null; 962 } 963 964 965 private void noSuchRecord(Object key) throws StorageException { 966 throw new StorageBadRequestException( 967 MessageFormat.format("No record exists with key {0}", 968 new Object [] {key} ) ); 969 } 970 971 972 private Object getRecord(MOFID mKey) throws StorageException { 973 Integer offset = (Integer )indexFile.getIfExists(mKey); 974 if (offset == null) { 975 return null; 976 } 977 978 Streamable data; 979 InputStream strm = dataFile.get(offset.intValue(), mKey.getSerialNumber()); 980 try { 981 DataInputStream inStream = new DataInputStream(strm); 982 data = this.readStreamable (inStream); 983 } 984 finally { 985 try { 986 strm.close(); 987 } 988 catch (IOException ex) { 989 throw new StorageIOException(ex); 990 } 991 } 992 return data; 993 } 994 995 996 private void fetchIndexIndex() throws StorageException { 997 if (indexIndex == null) { 998 indexIndex = (MofidIndex)getIfExists(BtreeFactory.indexIndexId); 999 if (indexIndex == null) { 1000 indexIndex = new MofidIndex(this.myStorage); 1001 add(BtreeFactory.indexIndexId, indexIndex); 1002 } 1003 indexIndex.setName("Index of secondary Indexes"); 1004 } 1005 } 1006 1007 1008 private void fetchClassIndex() throws StorageException { 1009 if (classIndex == null) { 1010 classIndex = (CounterIndex)getIfExists(BtreeFactory.classIndexId); 1011 if (classIndex == null) { 1012 classIndex = new CounterIndex(); 1013 classIndex.add(CLASS_INDEX_TYPE); 1015 add(BtreeFactory.classIndexId, classIndex); 1016 } 1017 else { 1018 Iterator itr = classIndex.iterator(); 1019 while (itr.hasNext()) { 1020 Map.Entry ent = (Map.Entry)itr.next(); 1021 try { 1022 int code = ((Integer )ent.getValue()).intValue(); 1023 while (classes.size() < code + 1) { 1024 classes.add(null); 1025 } 1026 classes.set(code, Class.forName((String )ent.getKey())); 1027 } catch (Exception ex) { 1028 throw new StoragePersistentDataException( 1029 ex.getMessage()); 1030 } 1031 } 1032 } 1033 classIndex.setName("Index of stored classes"); 1034 } 1035 } 1036 1037 1042 public java.util.Set keySet() throws StorageException { 1043 return new Keys(); 1044 } 1045 1046 1050 public java.util.Collection values () throws StorageException { 1051 return new Values(); 1052 } 1053 1054 1055 public void setLoggingStream(PrintStream strm) { 1056 synchronized (myStorage) { 1057 loggingStream = strm; 1058 } 1059 } 1060 1061 1062 public MofidGenerator getMofidGenerator() { 1063 synchronized (myStorage) { 1064 return dataFile; 1065 } 1066 } 1067 1068 private Map mofidMap = null; 1069 1070 1072 public Map getMofidMap() { 1073 synchronized (myStorage) { 1074 if (mofidMap == null) { 1077 mofidMap = new HashMap(); 1078 mofidMap.put(dataFile.getMofidPrefix(), dataFile); 1079 } 1080 return mofidMap; 1081 } 1082 } 1083 1084 1088 public int checkConsistency(PrintWriter strm) 1089 throws StorageException { 1090 1091 synchronized (myStorage) { 1092 1093 int numErrs = 1094 dataFile.dump(BtreeDataFile.DUMP_CONSISTENTCY_INFO, 0, false, strm); 1095 1096 1097 Iterator recordIter = dataFile.iterator( 1098 BtreeDataFile.ITERATE_NORMAL_EXTENTS); 1099 1100 while (recordIter.hasNext()) { 1101 NormalBtreeExtent ext = (NormalBtreeExtent)recordIter.next(); 1102 MOFID mKey = this.myStorage.readMOFIDData (new ByteArrayInputStream (ext.key)); 1103 Integer offset = (Integer )indexFile.getIfExists(mKey); 1104 if (offset == null) { 1105 strm.println("ID " + mKey + " is not in the index file."); 1106 numErrs++; 1107 } else if (offset.intValue() != ext.myChunkNum) { 1108 strm.println("ID " + mKey + " has differring offsets: " + 1109 ext.myChunkNum + " and " + offset.intValue()); 1110 numErrs++; 1111 } 1112 } 1113 1114 1115 Iterator actIter = cache.iterateActive(); 1116 while (actIter.hasNext()) { 1117 MOFID key = (MOFID)actIter.next(); 1118 if (cache.isDeleted(key)) { 1119 if (!cache.isNew(key)) { 1120 strm.println( 1121 "ID " + key + " is deleted and active but not new"); 1122 numErrs++; 1123 } 1124 } 1125 else { 1126 if (cache.isNew(key)) { 1127 if (inIndexFile(key)) { 1128 strm.println( 1129 "ID " + key + " is new but in the index file"); 1130 numErrs++; 1131 } 1132 } 1133 else { 1134 if (!inIndexFile(key)) { 1135 strm.println( 1136 "ID " + key + 1137 " exists but is not in the index file"); 1138 numErrs++; 1139 } 1140 } 1141 } 1142 } 1143 1144 Iterator delIter = cache.iterateDeleted(); 1145 while (delIter.hasNext()) { 1146 MOFID key = (MOFID)delIter.next(); 1147 if (!inIndexFile(key)) { 1148 strm.println( 1149 "ID " + key + " is deleted but not in the index file"); 1150 numErrs++; 1151 } 1152 } 1153 1154 numErrs += ((Btree)indexFile).consistencyCheck(strm); 1155 strm.println("" + numErrs + " error(s) detected."); 1156 strm.println(); 1157 cache.showStats(strm); 1158 strm.println(); 1159 fileCache.showStats(strm); 1160 strm.println(); 1161 strm.flush(); 1162 1163 return numErrs; 1164 } 1165 } 1166 1167 1168 1169 private boolean inIndexFile(MOFID key) throws StorageException { 1170 return indexFile.getIfExists(key) != null; 1171 } 1172 1173 1175 class KeyIterator implements Iterator { 1176 1177 1178 private int iterModLevel; 1179 1180 1181 private Iterator fileIter; 1182 1183 1184 private Iterator newIter; 1185 1186 1187 private MOFID nextKey; 1188 1189 1192 KeyIterator(boolean internal) { 1193 fileIter = dataFile.iterator(BtreeDataFile.ITERATE_KEYS); 1194 newIter = null; 1195 iterModLevel = modificationLevel; 1196 getNextKey(); 1197 } 1198 1199 1201 private void getNextKey() { 1202 nextKey = null; 1203 1204 synchronized(myStorage) { 1205 checkModLevel(); 1206 while (fileIter.hasNext()) { 1207 MOFID fileKey = (MOFID)fileIter.next(); 1208 if (!cache.isDeleted(fileKey)) { 1209 nextKey = fileKey; 1210 return; 1211 } 1212 } 1213 if (newIter == null) { 1214 newIter = cache.iterateNew(); 1215 } 1216 1217 if (newIter.hasNext()) { 1218 nextKey = (MOFID)newIter.next(); 1219 } 1220 } 1221 } 1222 1223 1224 public synchronized boolean hasNext() { 1225 return nextKey != null; 1226 } 1227 1228 1229 public synchronized Object next() { 1230 Object current = nextKey; 1231 getNextKey(); 1232 return current; 1233 } 1234 1235 1236 public void remove() { 1237 1238 throw new UnsupportedOperationException ( 1239 "Remove is not supported"); 1240 } 1241 1242 private void checkModLevel() { 1243 if (iterModLevel != modificationLevel) { 1244 throw new ConcurrentModificationException( 1245 "Database had been modified"); 1246 } 1247 } 1248 } 1249 1250 1252 class ValueIterator implements Iterator { 1253 1254 private Iterator keyIter; 1255 1256 ValueIterator() { 1257 synchronized (myStorage) { 1258 keyIter = new KeyIterator(true); 1259 } 1260 } 1261 1262 1265 public boolean hasNext() { 1266 return keyIter.hasNext(); 1267 } 1268 1269 1272 public Object next() { 1273 MOFID id = (MOFID)keyIter.next(); 1274 try { 1275 return get(id); 1276 } 1277 catch (StorageException ex) { 1278 throw new RuntimeStorageException(ex); 1279 } 1280 } 1281 1282 1285 public void remove() { 1286 1287 throw new UnsupportedOperationException ( 1288 "Remove is not supported"); 1289 } 1290 } 1291 1292 1293 1297 class Keys extends AbstractSet implements Set { 1298 1299 1302 public Iterator iterator() { 1303 synchronized (myStorage) { 1304 return new KeyIterator(false); 1305 } 1306 } 1307 1308 1311 public int size() { 1312 return BtreeDatabase.this.size(); 1313 } 1314 } 1315 1316 1323 class Values extends AbstractCollection implements Collection { 1324 1325 1328 public Iterator iterator() { 1329 return BtreeDatabase.this.new ValueIterator(); 1330 } 1331 1332 1335 public int size() { 1336 return BtreeDatabase.this.size(); 1337 } 1338 } 1339 1340} 1341 | Popular Tags |