1 29 30 package com.caucho.db.store; 31 32 import com.caucho.db.Database; 33 import com.caucho.lifecycle.Lifecycle; 34 import com.caucho.log.Log; 35 import com.caucho.sql.SQLExceptionWrapper; 36 import com.caucho.util.L10N; 37 import com.caucho.vfs.Path; 38 import com.caucho.vfs.RandomAccessStream; 39 40 import java.io.IOException ; 41 import java.lang.ref.SoftReference ; 42 import java.sql.SQLException ; 43 import java.util.logging.Level ; 44 import java.util.logging.Logger ; 45 46 86 public class Store { 87 private final static Logger log = Log.open(Store.class); 88 private final static L10N L = new L10N(Store.class); 89 90 public final static int BLOCK_BITS = 16; 91 public final static int BLOCK_SIZE = 1 << BLOCK_BITS; 92 public final static long BLOCK_INDEX_MASK = BLOCK_SIZE - 1; 93 public final static long BLOCK_MASK = ~ BLOCK_INDEX_MASK; 94 public final static long BLOCK_OFFSET_MASK = BLOCK_SIZE - 1; 95 96 private final static int ALLOC_BYTES_PER_BLOCK = 2; 97 98 private final static int ALLOC_CHUNK_SIZE = 1024 * ALLOC_BYTES_PER_BLOCK; 99 100 public final static int ALLOC_FREE = 0x00; 101 public final static int ALLOC_ROW = 0x01; 102 public final static int ALLOC_USED = 0x02; 103 public final static int ALLOC_FRAGMENT = 0x03; 104 public final static int ALLOC_INDEX = 0x04; 105 public final static int ALLOC_MASK = 0x0f; 106 107 public final static int FRAGMENT_SIZE = 8 * 1024; 108 public final static int FRAGMENT_PER_BLOCK 109 = (int) (BLOCK_SIZE / FRAGMENT_SIZE); 110 111 public final static long DATA_START = BLOCK_SIZE; 112 113 public final static int STORE_CREATE_END = 1024; 114 115 protected final Database _database; 116 protected final BlockManager _blockManager; 117 118 private final String _name; 119 120 private int _id; 121 122 private Path _path; 123 124 private boolean _isFlushDirtyBlocksOnCommit = true; 127 128 private long _fileSize; 129 private long _blockCount; 130 131 private final Object _allocationLock = new Object (); 132 private byte []_allocationTable; 133 134 private final Object _allocationWriteLock = new Object (); 135 private int _allocDirtyMin = Integer.MAX_VALUE; 136 private int _allocDirtyMax; 137 138 private final Object _fragmentLock = new Object (); 139 140 private final Object _statLock = new Object (); 141 private long _fragmentUseCount; 143 144 private SoftReference <RandomAccessWrapper> _cachedRowFile; 145 146 private Lock _rowLock; 147 148 private final Lifecycle _lifecycle = new Lifecycle(); 149 150 public Store(Database database, String name, Lock tableLock) 151 { 152 this(database, name, tableLock, database.getPath().lookup(name + ".db")); 153 } 154 155 163 public Store(Database database, String name, Lock rowLock, Path path) 164 { 165 _database = database; 166 _blockManager = _database.getBlockManager(); 167 168 _name = name; 169 _path = path; 170 171 if (path == null) 172 throw new NullPointerException (); 173 174 _id = _blockManager.allocateStoreId(); 175 176 if (rowLock == null) 177 rowLock = new Lock("row-lock:" + _name + ":" + _id); 178 179 _rowLock = rowLock; 180 } 181 182 185 public static Store create(Path path) 186 throws IOException , SQLException 187 { 188 Database db = new Database(); 189 db.init(); 190 191 Store store = new Store(db, "temp", null, path); 192 193 if (path.canRead()) 194 store.init(); 195 else 196 store.create(); 197 198 return store; 199 } 200 201 204 public void setFlushDirtyBlocksOnCommit(boolean flushOnCommit) 205 { 206 _isFlushDirtyBlocksOnCommit = flushOnCommit; 207 } 208 209 212 public boolean isFlushDirtyBlocksOnCommit() 213 { 214 return _isFlushDirtyBlocksOnCommit; 215 } 216 217 220 public String getName() 221 { 222 return _name; 223 } 224 225 228 public int getId() 229 { 230 return _id; 231 } 232 233 236 public Lock getLock() 237 { 238 return _rowLock; 239 } 240 241 244 public BlockManager getBlockManager() 245 { 246 return _blockManager; 247 } 248 249 252 public long getFileSize() 253 { 254 return _fileSize; 255 } 256 257 260 public long getBlockCount() 261 { 262 return _blockCount; 263 } 264 265 269 private static long blockIndexToAddr(long blockIndex) 270 { 271 return blockIndex << BLOCK_BITS; 272 } 273 274 277 private final long blockIndexToBlockId(long blockIndex) 278 { 279 return (blockIndex << BLOCK_BITS) + _id; 280 } 281 282 286 private static long blockIdToIndex(long blockId) 287 { 288 return blockId >> BLOCK_BITS; 289 } 290 291 294 public final long addressToBlockId(long address) 295 { 296 return (address & BLOCK_MASK) + _id; 297 } 298 299 302 public static long blockIdToAddress(long blockId) 303 { 304 return (blockId & BLOCK_MASK); 305 } 306 307 310 public static long blockIdToAddress(long blockId, int offset) 311 { 312 return (blockId & BLOCK_MASK) + offset; 313 } 314 315 318 public long getTotalFragmentSize() 319 { 320 return _fragmentUseCount * FRAGMENT_SIZE; 321 } 322 323 326 public void create() 327 throws IOException , SQLException 328 { 329 if (! _lifecycle.toActive()) 330 return; 331 332 log.finer(this + " create"); 333 334 _path.getParent().mkdirs(); 335 336 if (_path.exists()) 337 throw new SQLException (L.l("Table `{0}' already exists. CREATE can not override an existing table.", _name)); 338 339 _allocationTable = new byte[ALLOC_CHUNK_SIZE]; 340 341 setAllocation(0, ALLOC_USED); 343 setAllocation(1, ALLOC_USED); 345 346 byte []buffer = new byte[BLOCK_SIZE]; 347 writeBlock(0, buffer, 0, BLOCK_SIZE); 348 writeBlock(BLOCK_SIZE, buffer, 0, BLOCK_SIZE); 349 350 writeBlock(0, _allocationTable, 0, _allocationTable.length); 351 352 _blockCount = 2; 353 } 354 355 public void init() 356 throws IOException 357 { 358 if (! _lifecycle.toActive()) 359 return; 360 361 log.finer(this + " init"); 362 363 RandomAccessWrapper wrapper = openRowFile(); 364 365 try { 366 RandomAccessStream file = wrapper.getFile(); 367 368 _fileSize = file.getLength(); 369 _blockCount = ((_fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE); 370 371 int allocCount = (int) (_blockCount * ALLOC_BYTES_PER_BLOCK); 372 373 allocCount += ALLOC_CHUNK_SIZE - allocCount % ALLOC_CHUNK_SIZE; 374 375 _allocationTable = new byte[allocCount]; 376 377 for (int i = 0; i < allocCount; i += BLOCK_SIZE) { 378 int len = allocCount - i; 379 380 if (BLOCK_SIZE < len) 381 len = BLOCK_SIZE; 382 383 readBlock((long) i / ALLOC_BYTES_PER_BLOCK * BLOCK_SIZE, 384 _allocationTable, i, len); 385 } 386 } finally { 387 wrapper.close(); 388 } 389 } 390 391 public void remove() 392 throws SQLException 393 { 394 try { 395 _path.remove(); 396 } catch (IOException e) { 397 throw new SQLExceptionWrapper(e); 398 } 399 } 400 401 406 public long firstRow(long blockId) 407 throws IOException 408 { 409 return firstBlock(blockId, ALLOC_ROW); 410 } 411 412 417 public long firstFragment(long blockId) 418 throws IOException 419 { 420 return firstBlock(blockId, ALLOC_FRAGMENT); 421 } 422 423 428 public long firstBlock(long blockId, int type) 429 throws IOException 430 { 431 if (blockId <= BLOCK_SIZE) 432 blockId = BLOCK_SIZE; 433 434 long blockIndex = blockId >> BLOCK_BITS; 435 436 synchronized (_allocationLock) { 437 for (; blockIndex < _blockCount; blockIndex++) { 438 if (getAllocation(blockIndex) == type) 439 return blockIndexToBlockId(blockIndex); 440 } 441 } 442 443 return -1; 444 } 445 446 449 public final Block readBlock(long blockAddress) 450 throws IOException 451 { 452 long blockId = addressToBlockId(blockAddress); 453 454 Block block = _blockManager.getBlock(this, blockId); 455 456 try { 457 block.read(); 458 459 return block; 460 } catch (IOException e) { 461 block.free(); 462 463 throw e; 464 } catch (RuntimeException e) { 465 block.free(); 466 467 throw e; 468 } 469 } 470 471 476 public Block allocateRow() 477 throws IOException 478 { 479 return allocateBlock(ALLOC_ROW); 480 } 481 482 485 public boolean isRowBlock(long blockAddress) 486 { 487 return getAllocation(blockAddress / BLOCK_SIZE) == ALLOC_ROW; 488 } 489 490 495 public Block allocateBlock() 496 throws IOException 497 { 498 return allocateBlock(ALLOC_USED); 499 } 500 501 506 private Block allocateFragmentBlock() 507 throws IOException 508 { 509 return allocateBlock(ALLOC_FRAGMENT); 510 } 511 512 517 public Block allocateIndexBlock() 518 throws IOException 519 { 520 return allocateBlock(ALLOC_INDEX); 521 } 522 523 526 public boolean isIndexBlock(long blockAddress) 527 { 528 return getAllocation(blockAddress / BLOCK_SIZE) == ALLOC_INDEX; 529 } 530 531 536 private Block allocateBlock(int code) 537 throws IOException 538 { 539 long blockIndex; 540 boolean isFileExtended = false; 541 542 555 556 synchronized (_allocationLock) { 557 long end = _blockCount; 558 559 if (_allocationTable.length < ALLOC_BYTES_PER_BLOCK * end) 560 end = _allocationTable.length / ALLOC_BYTES_PER_BLOCK; 561 562 for (blockIndex = 0; blockIndex < end; blockIndex++) { 563 if (getAllocation(blockIndex) == ALLOC_FREE) 564 break; 565 } 566 567 if (_allocationTable.length <= ALLOC_BYTES_PER_BLOCK * blockIndex) { 568 byte []newTable = new byte[_allocationTable.length + ALLOC_CHUNK_SIZE]; 570 System.arraycopy(_allocationTable, 0, 571 newTable, 0, 572 _allocationTable.length); 573 _allocationTable = newTable; 574 575 if (blockIndex % (BLOCK_SIZE / ALLOC_BYTES_PER_BLOCK) == 0) { 578 setAllocation(blockIndex, ALLOC_USED); 579 blockIndex++; 580 } 581 } 582 583 setAllocation(blockIndex, ALLOC_USED); 585 586 if (log.isLoggable(Level.FINE)) 587 log.fine(this + " allocating block " + blockIndex + " " + codeToName(code)); 588 589 if (_blockCount <= blockIndex) { 590 isFileExtended = true; 591 _blockCount = blockIndex + 1; 592 } 593 } 594 595 long blockId = blockIndexToBlockId(blockIndex); 596 597 Block block = _blockManager.getBlock(this, blockId); 598 599 byte []buffer = block.getBuffer(); 600 601 for (int i = BLOCK_SIZE - 1; i >= 0; i--) 602 buffer[i] = 0; 603 604 block.setDirty(0, BLOCK_SIZE); 605 606 if (isFileExtended) { 608 try { 609 block.write(); 610 } catch (IOException e) { 611 log.log(Level.WARNING, e.toString(), e); 612 } 613 } 614 615 synchronized (_allocationLock) { 616 setAllocation(blockIndex, code); 617 } 618 619 saveAllocation(); 620 621 return block; 622 } 623 624 627 protected void validateBlockId(long blockId) 628 throws IllegalArgumentException , IllegalStateException 629 { 630 RuntimeException e = null; 631 632 if (isClosed()) 633 e = new IllegalStateException (L.l("store {0} is closing.", this)); 634 else if (getId() <= 0) 635 e = new IllegalStateException (L.l("invalid store {0}.", this)); 636 else if (getId() != (blockId & BLOCK_INDEX_MASK)) { 637 e = new IllegalArgumentException (L.l("block {0} must match store {1}.", 638 blockId & BLOCK_INDEX_MASK, 639 this)); 640 } 641 642 if (e != null) 643 throw e; 644 } 645 646 649 protected void assertStoreActive() 650 throws IllegalStateException 651 { 652 RuntimeException e = null; 653 654 if (isClosed()) 655 e = new IllegalStateException (L.l("store {0} is closing.", this)); 656 else if (getId() <= 0) 657 e = new IllegalStateException (L.l("invalid store {0}.", this)); 658 659 if (e != null) 660 throw e; 661 } 662 663 668 protected void freeBlock(long blockId) 669 throws IOException 670 { 671 if (blockId == 0) 672 return; 673 674 synchronized (_allocationLock) { 675 setAllocation(blockIdToIndex(blockId), ALLOC_FREE); 676 } 677 678 saveAllocation(); 679 } 680 681 684 private final int getAllocation(long blockIndex) 685 { 686 int allocOffset = (int) (ALLOC_BYTES_PER_BLOCK * blockIndex); 687 688 return _allocationTable[allocOffset] & ALLOC_MASK; 689 } 690 691 694 private void setAllocation(long blockIndex, int code) 695 { 696 int allocOffset = (int) (ALLOC_BYTES_PER_BLOCK * blockIndex); 697 698 for (int i = 1; i < ALLOC_BYTES_PER_BLOCK; i++) 699 _allocationTable[allocOffset + i] = 0; 700 701 _allocationTable[allocOffset] = (byte) code; 702 703 setAllocDirty(allocOffset, allocOffset + ALLOC_BYTES_PER_BLOCK); 704 } 705 706 709 private void setAllocDirty(int min, int max) 710 { 711 if (min < _allocDirtyMin) 712 _allocDirtyMin = min; 713 714 if (_allocDirtyMax < max) 715 _allocDirtyMax = max; 716 } 717 718 721 void saveAllocation() 722 throws IOException 723 { 724 if (! _isFlushDirtyBlocksOnCommit) 726 return; 727 728 synchronized (_allocationWriteLock) { 729 int dirtyMin; 730 int dirtyMax; 731 732 synchronized (_allocationLock) { 733 dirtyMin = _allocDirtyMin; 734 _allocDirtyMin = Integer.MAX_VALUE; 735 736 dirtyMax = _allocDirtyMax; 737 _allocDirtyMax = 0; 738 } 739 740 for (; 743 dirtyMin < dirtyMax; 744 dirtyMin = (dirtyMin + BLOCK_SIZE) - dirtyMin % BLOCK_SIZE) { 745 int block = dirtyMin / (BLOCK_SIZE / ALLOC_BYTES_PER_BLOCK); 746 747 int offset = dirtyMin % BLOCK_SIZE; 748 int length; 749 750 if (dirtyMin / BLOCK_SIZE != dirtyMax / BLOCK_SIZE) 751 length = BLOCK_SIZE - offset; 752 else 753 length = dirtyMax - dirtyMin; 754 755 writeBlock((long) block * BLOCK_SIZE + offset, 756 _allocationTable, offset, length); 757 } 758 } 759 } 760 761 772 public int readFragment(long fragmentAddress, int fragmentOffset, 773 byte []buffer, int offset, int length) 774 throws IOException 775 { 776 if (FRAGMENT_SIZE - fragmentOffset < length) { 777 throw new IllegalArgumentException (L.l("read offset {0} length {1} too long", 779 fragmentOffset, length)); 780 } 781 782 Block block = readBlock(addressToBlockId(fragmentAddress)); 783 784 try { 785 int blockOffset = getFragmentOffset(fragmentAddress); 786 787 byte []blockBuffer = block.getBuffer(); 788 789 synchronized (blockBuffer) { 790 System.arraycopy(blockBuffer, blockOffset + fragmentOffset, 791 buffer, offset, length); 792 } 793 794 return length; 795 } finally { 796 block.free(); 797 } 798 } 799 800 811 public int readFragment(long fragmentAddress, int fragmentOffset, 812 char []buffer, int offset, int length) 813 throws IOException 814 { 815 if (FRAGMENT_SIZE - fragmentOffset < 2 * length) { 816 throw new IllegalArgumentException (L.l("read offset {0} length {1} too long", 818 fragmentOffset, length)); 819 } 820 821 Block block = readBlock(addressToBlockId(fragmentAddress)); 822 823 try { 824 int blockOffset = getFragmentOffset(fragmentAddress); 825 blockOffset += fragmentOffset; 826 827 byte []blockBuffer = block.getBuffer(); 828 829 synchronized (blockBuffer) { 830 for (int i = 0; i < length; i++) { 831 int ch1 = blockBuffer[blockOffset] & 0xff; 832 int ch2 = blockBuffer[blockOffset + 1] & 0xff; 833 834 buffer[offset + i] = (char) ((ch1 << 8) + ch2); 835 836 blockOffset += 2; 837 } 838 } 839 840 return length; 841 } finally { 842 block.free(); 843 } 844 } 845 846 851 public long readFragmentLong(long fragmentAddress, 852 int fragmentOffset) 853 throws IOException 854 { 855 Block block = readBlock(addressToBlockId(fragmentAddress)); 856 857 try { 858 int blockOffset = getFragmentOffset(fragmentAddress); 859 860 byte []blockBuffer = block.getBuffer(); 861 862 synchronized (blockBuffer) { 863 return readLong(blockBuffer, blockOffset + fragmentOffset); 864 } 865 } finally { 866 block.free(); 867 } 868 } 869 870 875 public long allocateFragment(StoreTransaction xa) 876 throws IOException 877 { 878 while (true) { 879 synchronized (_allocationLock) { 880 byte []allocationTable = _allocationTable; 881 882 for (int i = 0; i < allocationTable.length; i += ALLOC_BYTES_PER_BLOCK) { 883 int fragMask = allocationTable[i + 1] & 0xff; 884 885 if (allocationTable[i] == ALLOC_FRAGMENT && fragMask != 0xff) { 886 for (int j = 0; j < FRAGMENT_PER_BLOCK; j++) { 887 if ((fragMask & (1 << j)) == 0) { 888 allocationTable[i + 1] = (byte) (fragMask | (1 << j)); 889 890 setAllocDirty(i + 1, i + 2); 891 892 _fragmentUseCount++; 893 894 long fragmentAddress 895 = BLOCK_SIZE * ((long) i / ALLOC_BYTES_PER_BLOCK) + j; 896 897 return fragmentAddress; 899 } 900 } 901 } 902 } 903 } 904 905 907 Block block = allocateFragmentBlock(); 908 block.free(); 909 } 910 } 911 912 915 public void deleteFragment(StoreTransaction xa, long fragmentAddress) 916 throws IOException 917 { 918 synchronized (_allocationLock) { 919 int i = (int) (ALLOC_BYTES_PER_BLOCK * (fragmentAddress / BLOCK_SIZE)); 920 int j = (int) (fragmentAddress & 0xff); 921 922 int fragMask = _allocationTable[i + 1] & 0xff; 923 925 if (_allocationTable[i] != ALLOC_FRAGMENT) 926 System.out.println("BAD ENTRY: " + fragMask); 927 928 if (j >= 8) 929 System.out.println("BAD J: " + fragMask); 930 931 if ((fragMask & (1 << j)) == 0) { 932 log.fine("BAD J-MASK: " + fragMask + " " + j); 933 } 934 935 _allocationTable[i + 1] = (byte) (fragMask & ~(1 << j)); 936 937 _fragmentUseCount--; 938 939 setAllocDirty(i + 1, i + 2); 940 } 941 } 942 943 955 public void writeFragment(StoreTransaction xa, 956 long fragmentAddress, int fragmentOffset, 957 byte []buffer, int offset, int length) 958 throws IOException 959 { 960 if (FRAGMENT_SIZE - fragmentOffset < length) 961 throw new IllegalArgumentException (L.l("write offset {0} length {1} too long", 962 fragmentOffset, length)); 963 964 Block block = xa.readBlock(this, addressToBlockId(fragmentAddress)); 965 966 try { 967 xa.addUpdateFragmentBlock(block); 968 969 int blockOffset = getFragmentOffset(fragmentAddress); 970 971 byte []blockBuffer = block.getBuffer(); 972 973 blockOffset += fragmentOffset; 974 975 synchronized (blockBuffer) { 976 System.arraycopy(buffer, offset, 977 blockBuffer, blockOffset, 978 length); 979 980 block.setDirty(blockOffset, blockOffset + length); 981 } 982 } finally { 983 block.free(); 984 } 985 } 986 987 996 public void writeFragment(StoreTransaction xa, 997 long fragmentAddress, int fragmentOffset, 998 char []buffer, int offset, int length) 999 throws IOException 1000 { 1001 if (FRAGMENT_SIZE - fragmentOffset < length) 1002 throw new IllegalArgumentException (L.l("write offset {0} length {1} too long", 1003 fragmentOffset, length)); 1004 1005 Block block = xa.readBlock(this, addressToBlockId(fragmentAddress)); 1006 1007 try { 1008 block = xa.createAutoCommitWriteBlock(block); 1009 1010 int blockOffset = getFragmentOffset(fragmentAddress); 1011 1012 byte []blockBuffer = block.getBuffer(); 1013 1014 blockOffset += fragmentOffset; 1015 1016 synchronized (blockBuffer) { 1017 int blockTail = blockOffset; 1018 1019 for (int i = 0; i < length; i++) { 1020 char ch = buffer[offset + i]; 1021 1022 blockBuffer[blockTail] = (byte) (ch >> 8); 1023 blockBuffer[blockTail + 1] = (byte) (ch); 1024 1025 blockTail += 2; 1026 } 1027 1028 block.setDirty(blockOffset, blockTail); 1029 } 1030 } finally { 1031 block.free(); 1032 } 1033 } 1034 1035 1040 public void writeFragmentLong(StoreTransaction xa, 1041 long fragmentAddress, int fragmentOffset, 1042 long value) 1043 throws IOException 1044 { 1045 Block block = xa.readBlock(this, addressToBlockId(fragmentAddress)); 1046 1047 try { 1048 xa.addUpdateBlock(block); 1049 1050 int blockOffset = getFragmentOffset(fragmentAddress); 1051 1052 byte []blockBuffer = block.getBuffer(); 1053 int offset = blockOffset + fragmentOffset; 1054 1055 synchronized (blockBuffer) { 1056 writeLong(blockBuffer, offset, value); 1057 1058 block.setDirty(offset, offset + 8); 1059 } 1060 } finally { 1061 block.free(); 1062 } 1063 } 1064 1065 1068 private int getFragmentOffset(long fragmentAddress) 1069 { 1070 int id = (int) (fragmentAddress & BLOCK_OFFSET_MASK); 1071 1072 return (int) (FRAGMENT_SIZE * id); 1073 } 1074 1075 1078 public void readBlock(long blockId, byte []buffer, int offset, int length) 1079 throws IOException 1080 { 1081 RandomAccessWrapper wrapper = openRowFile(); 1082 RandomAccessStream is = wrapper.getFile(); 1083 1084 long blockAddress = blockId & BLOCK_MASK; 1085 1086 try { 1087 if (blockAddress < 0 || _fileSize < blockAddress + length) { 1088 throw new IllegalStateException (L.l("block at {0} is invalid for file {1} (length {2})", 1089 Long.toHexString(blockAddress), 1090 _path, 1091 Long.toHexString(_fileSize))); 1092 } 1093 1094 int readLen = is.read(blockAddress, buffer, offset, length); 1095 1096 if (readLen < 0) { 1097 for (int i = 0; i < BLOCK_SIZE; i++) 1098 buffer[i] = 0; 1099 } 1100 1101 freeRowFile(wrapper); 1102 wrapper = null; 1103 } finally { 1104 if (wrapper != null) 1105 wrapper.close(); 1106 } 1107 } 1108 1109 1112 public void writeBlock(long blockAddress, 1113 byte []buffer, int offset, int length) 1114 throws IOException 1115 { 1116 RandomAccessWrapper wrapper = openRowFile(); 1117 RandomAccessStream os = wrapper.getFile(); 1118 1119 try { 1120 os.write(blockAddress, buffer, offset, length); 1121 1122 freeRowFile(wrapper); 1123 wrapper = null; 1124 1125 if (_fileSize < blockAddress + length) { 1126 _fileSize = blockAddress + length; 1127 } 1128 1129 } finally { 1130 if (wrapper != null) 1131 wrapper.close(); 1132 } 1133 } 1134 1135 1138 private RandomAccessWrapper openRowFile() 1139 throws IOException 1140 { 1141 RandomAccessStream file = null; 1142 RandomAccessWrapper wrapper = null; 1143 1144 synchronized (this) { 1145 SoftReference <RandomAccessWrapper> ref = _cachedRowFile; 1146 _cachedRowFile = null; 1147 1148 if (ref != null) { 1149 wrapper = ref.get(); 1150 } 1151 } 1152 1153 if (wrapper != null) 1154 file = wrapper.getFile(); 1155 1156 if (file == null) { 1157 file = _path.openRandomAccess(); 1158 1159 wrapper = new RandomAccessWrapper(file); 1160 } 1161 1162 return wrapper; 1163 } 1164 1165 private void freeRowFile(RandomAccessWrapper wrapper) 1166 throws IOException 1167 { 1168 synchronized (this) { 1169 if (_cachedRowFile == null) { 1170 _cachedRowFile = new SoftReference <RandomAccessWrapper>(wrapper); 1171 return; 1172 } 1173 } 1174 1175 wrapper.close(); 1176 } 1177 1178 1181 private static void writeShort(byte []buffer, int offset, int v) 1182 { 1183 buffer[offset + 0] = (byte) (v >> 8); 1184 buffer[offset + 1] = (byte) (v); 1185 } 1186 1187 1190 private static int readShort(byte []buffer, int offset) 1191 { 1192 return (((buffer[offset + 0] & 0xff) << 8) | 1193 ((buffer[offset + 1] & 0xff))); 1194 } 1195 1196 1199 public void flush() 1200 { 1201 if (_lifecycle.isActive()) { 1202 if (_blockManager != null) { 1203 _blockManager.flush(this); 1204 } 1205 } 1206 } 1207 1208 1211 public boolean isClosed() 1212 { 1213 return _lifecycle.isDestroyed(); 1214 } 1215 1216 1219 public void close() 1220 { 1221 if (! _lifecycle.toDestroy()) 1222 return; 1223 1224 log.finer(this + " closing"); 1225 1226 if (_blockManager != null) { 1227 _blockManager.freeStore(this); 1228 _blockManager.freeStoreId(_id); 1229 } 1230 1231 long id = _id; 1232 _id = 0; 1233 1234 _path = null; 1235 1236 RandomAccessWrapper wrapper = null; 1237 1238 SoftReference <RandomAccessWrapper> ref = _cachedRowFile; 1239 _cachedRowFile = null; 1240 1241 if (ref != null) 1242 wrapper = ref.get(); 1243 1244 if (wrapper != null) { 1245 try { 1246 wrapper.close(); 1247 } catch (Throwable e) { 1248 } 1249 } 1250 } 1251 1252 1256 public byte []getAllocationTable() 1257 { 1258 byte []table = new byte[_allocationTable.length]; 1259 1260 System.arraycopy(_allocationTable, 0, table, 0, table.length); 1261 1262 return table; 1263 } 1264 1265 private static IllegalStateException stateError(String msg) 1266 { 1267 IllegalStateException e = new IllegalStateException (msg); 1268 e.fillInStackTrace(); 1269 log.log(Level.WARNING, e.toString(), e); 1270 return e; 1271 } 1272 1273 1276 public static long readLong(byte []buffer, int offset) 1277 { 1278 return (((buffer[offset + 0] & 0xffL) << 56) + 1279 ((buffer[offset + 1] & 0xffL) << 48) + 1280 ((buffer[offset + 2] & 0xffL) << 40) + 1281 ((buffer[offset + 3] & 0xffL) << 32) + 1282 ((buffer[offset + 4] & 0xffL) << 24) + 1283 ((buffer[offset + 5] & 0xffL) << 16) + 1284 ((buffer[offset + 6] & 0xffL) << 8) + 1285 ((buffer[offset + 7] & 0xffL))); 1286 } 1287 1288 1291 public static void writeLong(byte []buffer, int offset, long v) 1292 { 1293 buffer[offset + 0] = (byte) (v >> 56); 1294 buffer[offset + 1] = (byte) (v >> 48); 1295 buffer[offset + 2] = (byte) (v >> 40); 1296 buffer[offset + 3] = (byte) (v >> 32); 1297 1298 buffer[offset + 4] = (byte) (v >> 24); 1299 buffer[offset + 5] = (byte) (v >> 16); 1300 buffer[offset + 6] = (byte) (v >> 8); 1301 buffer[offset + 7] = (byte) (v); 1302 } 1303 1304 1307 public static String codeToName(int code) 1308 { 1309 switch (code) { 1310 case ALLOC_FREE: 1311 return "free"; 1312 case ALLOC_ROW: 1313 return "row"; 1314 case ALLOC_USED: 1315 return "used"; 1316 case ALLOC_FRAGMENT: 1317 return "fragment"; 1318 case ALLOC_INDEX: 1319 return "index"; 1320 default: 1321 return String.valueOf(code); 1322 } 1323 } 1324 1325 public String toString() 1326 { 1327 return "Store[" + _id + "]"; 1328 } 1329 1330 static class RandomAccessWrapper { 1331 private RandomAccessStream _file; 1332 1333 RandomAccessWrapper(RandomAccessStream file) 1334 { 1335 _file = file; 1336 } 1337 1338 RandomAccessStream getFile() 1339 { 1340 return _file; 1341 } 1342 1343 void close() 1344 throws IOException 1345 { 1346 RandomAccessStream file = _file; 1347 _file = null; 1348 1349 if (file != null) 1350 file.close(); 1351 } 1352 1353 protected void finalize() 1354 throws Throwable 1355 { 1356 super.finalize(); 1357 1358 close(); 1359 } 1360 } 1361} 1362 | Popular Tags |