1 24 25 package com.mckoi.database; 26 27 import java.io.IOException ; 28 import java.io.OutputStream ; 29 import java.io.DataOutputStream ; 30 import java.io.ByteArrayOutputStream ; 31 import java.util.ArrayList ; 32 import com.mckoi.util.IntegerListInterface; 33 import com.mckoi.util.AbstractBlockIntegerList; 34 import com.mckoi.util.BlockIntegerList; 35 import com.mckoi.util.BlockIntegerList.IntArrayListBlock; 36 import com.mckoi.util.IntegerListBlockInterface; 37 import com.mckoi.util.IntegerIterator; 38 import com.mckoi.util.IntegerVector; 39 import com.mckoi.util.UserTerminal; 40 import com.mckoi.util.Cache; 41 import com.mckoi.store.Store; 42 import com.mckoi.store.Area; 43 import com.mckoi.store.MutableArea; 44 import com.mckoi.store.AreaWriter; 45 import com.mckoi.debug.*; 46 47 82 83 final class IndexSetStore { 84 85 88 private static final int MAGIC = 0x0CA90291; 89 90 91 94 private final DebugLogger debug; 95 96 99 private final TransactionSystem system; 100 101 104 private Store store; 105 106 111 private MutableArea start_area; 112 113 121 private long index_header_p; 122 private Area index_header_area; 123 124 138 private IndexBlock[] index_blocks; 139 140 141 142 145 public IndexSetStore(Store store, final TransactionSystem system) { 146 this.store = store; 147 this.system = system; 148 this.debug = system.Debug(); 149 } 150 151 152 155 private synchronized void deleteAllAreas(ArrayList list) { 156 157 if (store != null) { 158 159 try { 160 store.lockForWrite(); 161 162 int sz = list.size(); 163 for (int i = 0; i < sz; ++i) { 164 long id = ((Long ) list.get(i)).longValue(); 165 store.deleteArea(id); 166 } 167 168 } 169 catch (IOException e) { 170 debug.write(Lvl.ERROR, this, "Error when freeing old index block."); 171 debug.writeException(e); 172 } 173 finally { 174 store.unlockForWrite(); 175 } 176 177 } 178 } 179 180 181 183 187 private long createBlankIndexBlock() throws IOException { 188 AreaWriter a = store.createArea(16); 190 long index_block_p = a.getID(); 191 a.putInt(1); a.putInt(0); a.putLong(0); a.finish(); 196 197 return index_block_p; 198 } 199 200 202 207 public synchronized long create() throws IOException { 208 209 AreaWriter a = store.createArea(16); 211 index_header_p = a.getID(); 212 a.putInt(1); a.putInt(0); a.putLong(0); a.finish(); 216 217 index_header_area = store.getArea(index_header_p); 219 220 index_blocks = new IndexBlock[0]; 221 222 AreaWriter start_a = store.createArea(32); 224 long start_p = start_a.getID(); 225 start_a.putInt(MAGIC); 227 start_a.putInt(1); 229 start_a.putLong(index_header_p); 231 start_a.finish(); 232 233 start_area = store.getMutableArea(start_p); 235 236 return start_p; 237 } 238 239 243 public synchronized void init(long start_p) throws IOException { 244 245 start_area = store.getMutableArea(start_p); 247 248 int magic = start_area.getInt(); 249 if (magic != MAGIC) { 250 throw new IOException ("Magic value for index set does not match."); 251 } 252 int version = start_area.getInt(); 253 if (version != 1) { 254 throw new IOException ("Unknown version for index set."); 255 } 256 257 index_header_p = start_area.getLong(); 259 index_header_area = store.getArea(index_header_p); 260 261 version = index_header_area.getInt(); if (version != 1) { 264 throw new IOException ("Incorrect version"); 265 } 266 int reserved = index_header_area.getInt(); int index_count = (int) index_header_area.getLong(); 268 index_blocks = new IndexBlock[index_count]; 269 270 for (int i = 0; i < index_count; ++i) { 272 int type = index_header_area.getInt(); 273 int block_size = index_header_area.getInt(); 274 long index_block_p = index_header_area.getLong(); 275 if (type == 1) { 276 index_blocks[i] = new IndexBlock(i, block_size, index_block_p); 277 index_blocks[i].addReference(); 278 } 279 else { 280 throw new IOException ("Do not understand index type: " + type); 281 } 282 } 283 284 } 285 286 289 public synchronized void close() { 290 if (store != null) { 291 for (int i = 0; i < index_blocks.length; ++i) { 292 index_blocks[i].removeReference(); 293 } 294 store = null; 295 index_blocks = null; 296 } 297 } 298 299 313 public synchronized void copyAllFrom(IndexSet index_set) throws IOException { 314 315 if (index_blocks == null) { 317 throw new RuntimeException ( 318 "Can't copy because this IndexSetStore is not initialized."); 319 } 320 321 for (int i = 0; i < index_blocks.length; ++i) { 323 commitDropIndex(i); 324 } 325 326 if (index_set instanceof SnapshotIndexSet) { 327 SnapshotIndexSet s_index_set = (SnapshotIndexSet) index_set; 329 330 int index_count = s_index_set.snapshot_index_blocks.length; 332 333 long old_index_header_p = index_header_p; 335 336 AreaWriter a = store.createArea(16 + (16 * index_count)); 338 index_header_p = a.getID(); 339 a.putInt(1); a.putInt(0); a.putLong(index_count); 343 for (int i = 0; i < index_count; ++i) { 345 IndexBlock source_block = s_index_set.snapshot_index_blocks[i]; 346 347 long index_block_p = source_block.copyTo(store); 348 349 a.putInt(1); a.putInt(source_block.getBlockSize()); 351 a.putLong(index_block_p); 352 } 353 354 a.finish(); 356 357 start_area.position(8); 359 start_area.putLong(index_header_p); 360 start_area.checkOut(); 362 363 store.deleteArea(old_index_header_p); 365 } 366 else { 367 throw new RuntimeException ("Can not copy non-IndexSetStore IndexSet"); 368 } 369 370 init(start_area.getID()); 372 } 373 374 378 public void addAllAreasUsed(ArrayList list) throws IOException { 379 list.add(new Long (start_area.getID())); 380 list.add(new Long (index_header_p)); 381 for (int i = 0; i < index_blocks.length; ++i) { 382 IndexBlock block = index_blocks[i]; 383 list.add(new Long (block.getPointer())); 384 long[] block_pointers = block.getAllBlockPointers(); 385 for (int n = 0; n < block_pointers.length; ++n) { 386 list.add(new Long (block_pointers[n])); 387 } 388 } 389 } 390 391 398 public synchronized void addIndexLists(int count, int type, int block_size) 399 throws IOException { 400 401 try { 402 store.lockForWrite(); 403 404 int new_size = 16 + ((index_blocks.length + count) * 16); 406 AreaWriter new_index_area = store.createArea(new_size); 407 long new_index_p = new_index_area.getID(); 408 IndexBlock[] new_index_blocks = 409 new IndexBlock[(index_blocks.length + count)]; 410 411 index_header_area.position(0); 413 int version = index_header_area.getInt(); 414 int reserved = index_header_area.getInt(); 415 long icount = index_header_area.getLong(); 416 new_index_area.putInt(version); 417 new_index_area.putInt(reserved); 418 new_index_area.putLong(icount + count); 419 420 for (int i = 0; i < index_blocks.length; ++i) { 421 int itype = index_header_area.getInt(); 422 int iblock_size = index_header_area.getInt(); 423 long index_block_p = index_header_area.getLong(); 424 425 new_index_area.putInt(itype); 426 new_index_area.putInt(iblock_size); 427 new_index_area.putLong(index_block_p); 428 429 new_index_blocks[i] = index_blocks[i]; 430 } 431 432 for (int i = 0; i < count; ++i) { 434 long new_blank_block_p = createBlankIndexBlock(); 435 436 new_index_area.putInt(type); 437 new_index_area.putInt(block_size); 438 new_index_area.putLong(new_blank_block_p); 439 440 IndexBlock i_block = new IndexBlock(index_blocks.length + i, 441 block_size, new_blank_block_p); 442 i_block.addReference(); 443 new_index_blocks[index_blocks.length + i] = i_block; 444 445 } 446 447 new_index_area.finish(); 449 450 long old_index_header_p = index_header_p; 452 453 index_header_p = new_index_p; 455 index_header_area = store.getArea(new_index_p); 456 index_blocks = new_index_blocks; 457 458 start_area.position(8); 460 start_area.putLong(new_index_p); 461 start_area.checkOut(); 462 463 store.deleteArea(old_index_header_p); 465 466 } 467 finally { 468 store.unlockForWrite(); 469 } 470 471 } 472 473 484 public synchronized IndexSet getSnapshotIndexSet() { 485 IndexBlock[] snapshot_index_blocks = (IndexBlock[]) index_blocks.clone(); 488 489 for (int i = 0; i < snapshot_index_blocks.length; ++i) { 491 snapshot_index_blocks[i].addReference(); 492 } 493 494 return new SnapshotIndexSet(snapshot_index_blocks); 495 } 496 497 500 private synchronized void commitIndexHeader() throws IOException { 501 502 AreaWriter a = store.createArea(16 + (index_blocks.length * 16)); 504 long a_p = a.getID(); 505 506 a.putInt(1); a.putInt(0); a.putLong(index_blocks.length); 510 for (int i = 0; i < index_blocks.length; ++i) { 511 IndexBlock ind_block = index_blocks[i]; 512 a.putInt(1); 513 a.putInt(ind_block.getBlockSize()); 514 a.putLong(ind_block.getPointer()); 515 } 516 517 a.finish(); 519 520 long old_index_header_p = index_header_p; 522 523 index_header_p = a_p; 525 index_header_area = store.getArea(index_header_p); 526 527 start_area.position(8); 529 start_area.putLong(index_header_p); 530 start_area.checkOut(); 531 532 store.deleteArea(old_index_header_p); 534 535 } 536 537 551 public void commitIndexSet(IndexSet index_set) { 552 553 ArrayList removed_blocks = new ArrayList (); 554 555 synchronized(this) { 556 557 SnapshotIndexSet s_index_set = (SnapshotIndexSet) index_set; 558 IndexIntegerList[] lists = s_index_set.getAllLists(); 559 560 try { 561 562 try { 563 store.lockForWrite(); 564 565 for (int n = 0; n < lists.length; ++n) { 567 IndexIntegerList list = (IndexIntegerList) lists[n]; 569 int index_num = list.getIndexNumber(); 570 IndexBlock cur_index_block = index_blocks[index_num]; 572 MappedListBlock[] blocks = list.getAllBlocks(); 574 575 AreaWriter a = store.createArea(16 + (blocks.length * 28)); 577 long block_p = a.getID(); 578 a.putInt(1); a.putInt(0); a.putLong(blocks.length); for (int i = 0; i < blocks.length; ++i) { 582 MappedListBlock b = blocks[i]; 583 584 long bottom_int = 0; 585 long top_int = 0; 586 int block_size = b.size(); 587 if (block_size > 0) { 588 bottom_int = b.bottomInt(); 589 top_int = b.topInt(); 590 } 591 long b_p = b.getBlockPointer(); 592 if (b_p == -1 || b.hasChanged()) { 594 if (b_p != -1) { 597 cur_index_block.addDeletedArea(b_p); 598 } 599 b_p = b.writeToStore(); 602 } 603 a.putLong(bottom_int); 604 a.putLong(top_int); 605 a.putLong(b_p); 606 a.putInt(block_size | (((int) b.getCompactType()) << 24)); 607 608 } 609 610 a.finish(); 612 613 MappedListBlock[] deleted_blocks = list.getDeletedBlocks(); 615 for (int i = 0; i < deleted_blocks.length; ++i) { 616 long del_block_p = deleted_blocks[i].getBlockPointer(); 617 if (del_block_p != -1) { 618 cur_index_block.addDeletedArea(del_block_p); 619 } 620 } 621 622 cur_index_block.markAsDeleted(); 624 625 IndexBlock new_index_block = 627 new IndexBlock(index_num, cur_index_block.getBlockSize(), block_p); 628 new_index_block.setParentIndexBlock(cur_index_block); 629 630 new_index_block.addReference(); 632 index_blocks[index_num] = new_index_block; 634 635 removed_blocks.add(cur_index_block); 637 638 } 639 640 commitIndexHeader(); 642 643 } 644 finally { 645 store.unlockForWrite(); 646 } 647 648 650 } 651 catch (IOException e) { 652 debug.writeException(e); 653 throw new Error ("IO Error: " + e.getMessage()); 654 } 655 656 } 658 int sz = removed_blocks.size(); 660 for (int i = 0; i < sz; ++i) { 661 IndexBlock block = (IndexBlock) removed_blocks.get(i); 662 block.removeReference(); 663 } 664 665 } 666 667 673 public synchronized void commitDropIndex(int index_num) throws IOException { 674 IndexBlock cur_index_block = index_blocks[index_num]; 676 int block_size = cur_index_block.getBlockSize(); 677 678 try { 679 store.lockForWrite(); 680 681 long[] all_block_pointers = cur_index_block.getAllBlockPointers(); 683 for (int i = 0; i < all_block_pointers.length; ++i) { 684 cur_index_block.addDeletedArea(all_block_pointers[i]); 685 } 686 687 cur_index_block.markAsDeleted(); 689 690 long block_p = createBlankIndexBlock(); 692 693 IndexBlock new_index_block = new IndexBlock(index_num, block_size, block_p); 695 696 new_index_block.addReference(); 698 cur_index_block.removeReference(); 700 index_blocks[index_num] = new_index_block; 702 703 commitIndexHeader(); 705 706 } 707 finally { 708 store.unlockForWrite(); 709 } 710 711 } 712 713 714 715 716 718 719 722 private static IndexIntegerList[] EMPTY_INTEGER_LISTS = 723 new IndexIntegerList[0]; 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 742 private class SnapshotIndexSet implements IndexSet { 743 744 748 private IndexBlock[] snapshot_index_blocks; 749 750 754 private ArrayList integer_lists; 755 756 759 private boolean disposed; 760 761 762 765 public SnapshotIndexSet(IndexBlock[] blocks) { 766 767 this.snapshot_index_blocks = blocks; 768 769 disposed = false; 771 772 } 773 774 778 public IndexIntegerList[] getAllLists() { 779 if (integer_lists == null) { 780 return EMPTY_INTEGER_LISTS; 781 } 782 else { 783 return (IndexIntegerList[]) integer_lists.toArray( 784 new IndexIntegerList[integer_lists.size()]); 785 } 786 } 787 788 790 public IntegerListInterface getIndex(int n) { 791 if (integer_lists == null) { 793 integer_lists = new ArrayList (); 794 } 795 else { 796 for (int o = 0; o < integer_lists.size(); ++o) { 798 IndexIntegerList i_list = (IndexIntegerList) integer_lists.get(o); 799 if (i_list.getIndexNumber() == n) { 800 return i_list; 801 } 804 } 805 } 806 807 try { 808 809 IndexIntegerList ilist = 810 snapshot_index_blocks[n].createIndexIntegerList(); 811 integer_lists.add(ilist); 812 return ilist; 813 814 } 815 catch (IOException e) { 816 debug.writeException(e); 817 throw new RuntimeException ("IO Error: " + e.getMessage()); 818 } 819 820 } 821 822 public void dispose() { 823 if (!disposed) { 824 825 if (integer_lists != null) { 826 for (int i = 0; i < integer_lists.size(); ++i) { 827 IndexIntegerList ilist = (IndexIntegerList) integer_lists.get(i); 828 ilist.dispose(); 829 } 830 integer_lists = null; 831 } 832 833 for (int i = 0; i < snapshot_index_blocks.length; ++i) { 835 IndexBlock iblock = snapshot_index_blocks[i]; 836 iblock.removeReference(); 837 } 838 snapshot_index_blocks = null; 839 840 disposed = true; 841 } 842 } 843 844 public void finalize() { 845 try { 846 if (!disposed) { 847 dispose(); 848 } 849 } 850 catch (Throwable e) { 851 debug.write(Lvl.ERROR, this, "Finalize error: " + e.getMessage()); 852 debug.writeException(e); 853 } 854 } 855 856 } 857 858 862 private final class MappedListBlock extends IntArrayListBlock { 863 864 867 private long first_entry; 868 869 872 private long last_entry; 873 874 877 private long block_p; 878 879 882 private Object lock = new Object (); 883 884 887 private boolean mutable_block; 888 889 893 private byte compact_type; 894 895 898 private final int max_block_size; 899 900 903 public MappedListBlock(long first_e, long last_e, 904 long mapped_p, int size, byte compact_type, 905 int max_block_size) { 906 this.first_entry = first_e; 907 this.last_entry = last_e; 908 this.block_p = mapped_p; 909 this.compact_type = compact_type; 910 this.max_block_size = max_block_size; 911 count = size; 912 array = null; 913 } 914 915 918 public MappedListBlock(int block_size_in) { 919 super(block_size_in); 920 this.block_p = -1; 921 this.max_block_size = block_size_in; 922 } 923 924 927 public long getBlockPointer() { 928 return block_p; 929 } 930 931 934 public byte getCompactType() { 935 return compact_type; 936 } 937 938 942 public long copyTo(Store dest_store) throws IOException { 943 int entry_size = compact_type; 945 int area_size = (count * entry_size); 947 948 AreaWriter dest = dest_store.createArea(area_size); 950 long dest_block_p = dest.getID(); 951 store.getArea(block_p).copyTo(dest, area_size); 952 dest.finish(); 953 954 return dest_block_p; 955 } 956 957 963 public long writeToStore() throws IOException { 964 966 long largest_val = 0; 969 for (int i = 0; i < count; ++i) { 970 long v = (long) array[i]; 971 if (Math.abs(v) > Math.abs(largest_val)) { 972 largest_val = v; 973 } 974 } 975 976 long lv = largest_val; 977 if (lv >> 7 == 0 || lv >> 7 == -1) { 978 compact_type = 1; 979 } 980 else if (lv >> 15 == 0 || lv >> 15 == -1) { 981 compact_type = 2; 982 } 983 else if (lv >> 23 == 0 || lv >> 23 == -1) { 984 compact_type = 3; 985 } 986 else { 989 compact_type = 4; 990 } 991 992 int entry_size = compact_type; 994 int area_size = (count * entry_size); 996 997 byte[] arr = new byte[area_size]; 999 int p = 0; 1001 for (int i = 0; i < count; ++i) { 1002 int v = array[i]; 1003 for (int n = entry_size - 1; n >= 0; --n) { 1004 arr[p] = (byte) ((v >>> (n * 8)) & 0x0FF); 1005 ++p; 1006 } 1007 } 1008 1009 AreaWriter a = store.createArea(area_size); 1011 block_p = a.getID(); 1012 a.put(arr, 0, area_size); 1014 a.finish(); 1016 1017 lock = null; 1019 1020 return block_p; 1021 } 1022 1023 1029 public int[] getArray(boolean immutable) { 1030 synchronized (lock) { 1033 1034 if (array != null) { 1035 prepareMutate(immutable); 1036 return array; 1037 } 1038 1039 array = new int[max_block_size]; 1041 1042 int entry_size = compact_type; 1044 int area_size = (count * entry_size); 1046 1047 byte[] buf = new byte[area_size]; 1049 try { 1050 store.getArea(block_p).get(buf, 0, area_size); 1051 } 1052 catch (IOException e) { 1053 debug.write(Lvl.ERROR, this, "block_p = " + block_p); 1054 debug.writeException(e); 1055 throw new Error ("IO Error: " + e.getMessage()); 1056 } 1057 1058 int p = 0; 1060 for (int i = 0; i < count; ++i) { 1061 int v = (((int) buf[p]) << ((entry_size - 1) * 8)); 1062 ++p; 1063 for (int n = entry_size - 2; n >= 0; --n) { 1064 v = v | ((((int) buf[p]) & 0x0FF) << (n * 8)); 1065 ++p; 1066 } 1067 array[i] = v; 1068 } 1069 1070 mutable_block = false; 1071 prepareMutate(immutable); 1072 return array; 1073 1074 } 1075 1076 } 1077 1078 1081 public int getArrayLength() { 1082 return max_block_size; 1083 } 1084 1085 1089 private void prepareMutate(boolean immutable) { 1090 if (!immutable && !mutable_block) { 1092 array = (int[]) array.clone(); 1093 mutable_block = true; 1094 } 1095 } 1096 1097 1100 public int topInt() { 1101 if (count == 0) { 1102 throw new Error ("No first int in block."); 1103 } 1104 1105 synchronized (lock) { 1106 if (array == null) { 1107 return (int) last_entry; 1108 } 1109 else { 1110 return array[count - 1]; 1111 } 1112 } 1113 } 1114 1115 1119 public int bottomInt() { 1120 if (count == 0) { 1121 throw new Error ("No first int in block."); 1122 } 1123 1124 synchronized (lock) { 1125 if (array == null) { 1126 return (int) first_entry; 1127 } 1128 else { 1129 return array[0]; 1130 } 1131 } 1132 } 1133 1134 } 1135 1136 1137 1138 1139 1143 private final class IndexIntegerList extends AbstractBlockIntegerList { 1144 1145 1148 private int index_num; 1149 1150 1153 private int max_block_size; 1154 1155 1158 private boolean disposed = false; 1159 1160 1163 private ArrayList deleted_blocks = new ArrayList (); 1164 1165 1166 1169 public IndexIntegerList(int index_num, int max_block_size, 1170 MappedListBlock[] blocks) { 1171 super(blocks); 1172 this.index_num = index_num; 1173 this.max_block_size = max_block_size; 1174 } 1175 1176 1179 protected IntegerListBlockInterface newListBlock() { 1180 if (!disposed) { 1181 return new MappedListBlock(max_block_size); 1182 } 1183 throw new Error ("Integer list has been disposed."); 1184 } 1185 1186 1189 protected void deleteListBlock(IntegerListBlockInterface list_block) { 1190 deleted_blocks.add(list_block); 1191 } 1192 1193 1196 public int getIndexNumber() { 1197 return index_num; 1198 } 1199 1200 1203 public MappedListBlock[] getAllBlocks() { 1204 return (MappedListBlock[]) 1205 block_list.toArray(new MappedListBlock[block_list.size()]); 1206 } 1207 1208 1212 public MappedListBlock[] getDeletedBlocks() { 1213 return (MappedListBlock[]) 1214 deleted_blocks.toArray(new MappedListBlock[deleted_blocks.size()]); 1215 } 1216 1217 1218 public void dispose() { 1219 disposed = true; 1220 block_list = null; 1221 } 1222 1223 } 1224 1225 1240 private class IndexBlock { 1241 1242 1246 private int reference_count; 1247 1248 1251 private int index_num; 1252 1253 1256 private final long index_block_p; 1257 1258 1261 private long block_entries; 1262 1263 1266 private final int block_size; 1267 1268 1272 private ArrayList deleted_areas; 1273 1274 1277 private boolean deleted = false; 1278 1279 1282 private boolean freed = false; 1283 1284 1287 private IndexBlock parent_block; 1288 1289 1292 IndexBlock(int index_num, int block_size, long index_block_p) 1293 throws IOException { 1294 this.index_num = index_num; 1295 this.block_size = block_size; 1296 this.index_block_p = index_block_p; 1297 1298 Area index_block_area = store.getArea(index_block_p); 1300 index_block_area.position(8); 1301 block_entries = index_block_area.getLong(); 1302 1303 reference_count = 0; 1304 1305 } 1306 1307 1310 void setParentIndexBlock(IndexBlock parent) { 1311 this.parent_block = parent; 1312 } 1313 1314 1317 long[] getAllBlockPointers() throws IOException { 1318 Area index_block_area = store.getArea(index_block_p); 1320 1321 long[] blocks = new long[(int) block_entries]; 1323 if (block_entries != 0) { 1324 index_block_area.position(16); 1325 for (int i = 0; i < block_entries; ++i) { 1326 index_block_area.getLong(); 1328 index_block_area.getLong(); 1329 long element_p = index_block_area.getLong(); 1330 index_block_area.getInt(); 1331 1332 blocks[i] = element_p; 1333 } 1334 } 1335 1336 return blocks; 1337 } 1338 1339 1343 private MappedListBlock[] createMappedListBlocks() throws IOException { 1344 Area index_block_area = store.getArea(index_block_p); 1346 MappedListBlock[] blocks = new MappedListBlock[(int) block_entries]; 1348 if (block_entries != 0) { 1349 index_block_area.position(16); 1350 for (int i = 0; i < block_entries; ++i) { 1351 long first_entry = index_block_area.getLong(); 1353 long last_entry = index_block_area.getLong(); 1354 long element_p = index_block_area.getLong(); 1355 int type_size = index_block_area.getInt(); 1356 1357 int element_count = type_size & 0x0FFF; 1359 byte type = (byte) ((type_size >>> 24) & 0x0F); 1360 1361 blocks[i] = new MappedListBlock(first_entry, last_entry, element_p, 1362 element_count, type, block_size); 1363 } 1364 } 1365 return blocks; 1366 } 1367 1368 1372 IndexIntegerList createIndexIntegerList() throws IOException { 1373 MappedListBlock[] blocks = createMappedListBlocks(); 1375 return new IndexIntegerList(index_num, block_size, blocks); 1377 } 1378 1379 1383 long copyTo(Store dest_store) throws IOException { 1384 MappedListBlock[] blocks = createMappedListBlocks(); 1386 try { 1387 dest_store.lockForWrite(); 1388 AreaWriter a = dest_store.createArea(16 + (blocks.length * 28)); 1390 long block_p = a.getID(); 1391 1392 a.putInt(1); a.putInt(0); a.putLong(blocks.length); for (int i = 0; i < blocks.length; ++i) { 1396 MappedListBlock entry = blocks[i]; 1397 long b_p = entry.copyTo(dest_store); 1398 int block_size = entry.size(); 1399 a.putLong(entry.first_entry); 1400 a.putLong(entry.last_entry); 1401 a.putLong(b_p); 1402 a.putInt(block_size | (((int) entry.getCompactType()) << 24)); 1403 } 1404 1405 a.finish(); 1407 1408 return block_p; 1410 1411 } 1412 finally { 1413 dest_store.unlockForWrite(); 1414 } 1415 1416 } 1417 1418 1422 private boolean deleteBlockChain() { 1423 boolean parent_deleted = true; 1424 if (parent_block != null) { 1425 parent_deleted = parent_block.deleteBlockChain(); 1426 if (parent_deleted) { 1427 parent_block = null; 1428 } 1429 } 1430 1431 if (parent_deleted) { 1433 if (reference_count <= 0) { 1435 if (deleted && deleted_areas != null) { 1436 deleteAllAreas(deleted_areas); 1437 } 1438 deleted_areas = null; 1439 } 1440 else { 1441 return false; 1443 } 1444 } 1445 1446 return parent_deleted; 1447 } 1448 1449 1452 public synchronized void addReference() { 1453 if (freed) { 1454 throw new RuntimeException ("Assertion failed: Block was freed."); 1455 } 1456 ++reference_count; 1457 } 1458 1459 1462 public void removeReference() { 1463 boolean pending_delete = false; 1464 synchronized(this) { 1465 --reference_count; 1466 if (reference_count <= 0) { 1467 if (freed) { 1468 throw new RuntimeException ( 1469 "Assertion failed: remove reference called too many times."); 1470 } 1471 if (!deleted && deleted_areas != null) { 1472 throw new RuntimeException ( 1473 "Assertion failed: !deleted and deleted_areas != null"); 1474 } 1475 freed = true; 1476 if (deleted) { 1477 addDeletedArea(index_block_p); 1478 pending_delete = true; 1480 } 1481 } 1482 } if (pending_delete) { 1484 synchronized(IndexSetStore.this) { 1485 deleteBlockChain(); 1486 } 1487 } 1488 } 1489 1490 1493 public synchronized int getReferenceCount() { 1494 return reference_count; 1495 } 1496 1497 1500 public int getBlockSize() { 1501 return block_size; 1502 } 1503 1504 1507 public long getPointer() { 1508 return index_block_p; 1509 } 1510 1511 1514 public synchronized void markAsDeleted() { 1515 deleted = true; 1516 } 1517 1518 1521 public synchronized void addDeletedArea(long pointer) { 1522 if (deleted_areas == null) { 1523 deleted_areas = new ArrayList (); 1524 } 1525 1526 deleted_areas.add(new Long (pointer)); 1527 1528 } 1529 1530 } 1531 1532} 1533 1534 | Popular Tags |