1 24 25 package com.mckoi.database; 26 27 import java.io.*; 28 import java.util.Iterator ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.List ; 32 import com.mckoi.util.IntegerListInterface; 33 import com.mckoi.util.IntegerIterator; 34 import com.mckoi.util.IntegerVector; 35 import com.mckoi.util.ByteArrayUtil; 36 import com.mckoi.util.UserTerminal; 37 import com.mckoi.util.BigNumber; 38 import com.mckoi.debug.*; 39 40 import com.mckoi.store.Store; 41 import com.mckoi.store.MutableArea; 42 import com.mckoi.store.Area; 43 44 import com.mckoi.database.StateStore.StateResource; 45 46 import com.mckoi.database.global.ByteLongObject; 47 import com.mckoi.database.global.ObjectTranslator; 48 import com.mckoi.database.global.Ref; 49 50 58 59 public class TableDataConglomerate { 60 61 64 public static final String STATE_POST = "_sf"; 65 66 68 72 public static final String SYSTEM_SCHEMA = "SYS_INFO"; 73 74 77 public static final TableName SCHEMA_INFO_TABLE = 78 new TableName(SYSTEM_SCHEMA, "sUSRSchemaInfo"); 79 80 public static final TableName PERSISTENT_VAR_TABLE = 81 new TableName(SYSTEM_SCHEMA, "sUSRDatabaseVars"); 82 83 public static final TableName FOREIGN_COLS_TABLE = 84 new TableName(SYSTEM_SCHEMA, "sUSRForeignColumns"); 85 86 public static final TableName UNIQUE_COLS_TABLE = 87 new TableName(SYSTEM_SCHEMA, "sUSRUniqueColumns"); 88 89 public static final TableName PRIMARY_COLS_TABLE = 90 new TableName(SYSTEM_SCHEMA, "sUSRPrimaryColumns"); 91 92 public static final TableName CHECK_INFO_TABLE = 93 new TableName(SYSTEM_SCHEMA, "sUSRCheckInfo"); 94 95 public static final TableName UNIQUE_INFO_TABLE = 96 new TableName(SYSTEM_SCHEMA, "sUSRUniqueInfo"); 97 98 public static final TableName FOREIGN_INFO_TABLE = 99 new TableName(SYSTEM_SCHEMA, "sUSRFKeyInfo"); 100 101 public static final TableName PRIMARY_INFO_TABLE = 102 new TableName(SYSTEM_SCHEMA, "sUSRPKeyInfo"); 103 104 public static final TableName SYS_SEQUENCE_INFO = 105 new TableName(SYSTEM_SCHEMA, "sUSRSequenceInfo"); 106 107 public static final TableName SYS_SEQUENCE = 108 new TableName(SYSTEM_SCHEMA, "sUSRSequence"); 109 110 113 private final TransactionSystem system; 114 115 119 private final StoreSystem store_system; 120 121 124 private String name; 125 126 129 private Store act_state_store; 130 131 135 private StateStore state_store; 136 137 141 private long commit_id; 142 143 144 148 private ArrayList table_list; 149 150 154 private Store act_blob_store; 155 156 159 private BlobStore blob_store; 160 161 164 private SequenceManager sequence_manager; 165 166 171 private OpenTransactionList open_transactions; 172 173 177 private ArrayList namespace_journal_list; 178 179 181 185 private final HashMap modification_listeners; 186 187 188 189 190 192 197 final Object commit_lock = new Object (); 198 199 207 208 209 210 213 public TableDataConglomerate(TransactionSystem system, 214 StoreSystem store_system) { 215 this.system = system; 216 this.store_system = store_system; 217 this.open_transactions = new OpenTransactionList(system); 218 this.modification_listeners = new HashMap (); 219 this.namespace_journal_list = new ArrayList (); 220 221 this.sequence_manager = new SequenceManager(this); 222 223 } 224 225 228 public final TransactionSystem getSystem() { 229 return system; 230 } 231 232 236 public final StoreSystem storeSystem() { 237 return store_system; 238 } 239 240 243 final SequenceManager getSequenceManager() { 244 return sequence_manager; 245 } 246 247 250 final BlobStore getBlobStore() { 251 return blob_store; 252 } 253 254 257 public final DebugLogger Debug() { 258 return getSystem().Debug(); 259 } 260 261 264 String getName() { 265 return name; 266 } 267 268 270 273 private void markAsCommittedDropped(int table_id) { 274 MasterTableDataSource master_table = getMasterTable(table_id); 275 state_store.addDeleteResource( 276 new StateResource(table_id, createEncodedTableFile(master_table))); 277 } 278 279 284 private MasterTableDataSource loadMasterTable(int table_id, 285 String table_str, int table_type) throws IOException { 286 287 if (table_type == 1) { 289 V1MasterTableDataSource master = 290 new V1MasterTableDataSource(getSystem(), 291 storeSystem(), open_transactions); 292 if (master.exists(table_str)) { 293 return master; 294 } 295 } 296 else if (table_type == 2) { 297 V2MasterTableDataSource master = 298 new V2MasterTableDataSource(getSystem(), 299 storeSystem(), open_transactions, blob_store); 300 if (master.exists(table_str)) { 301 return master; 302 } 303 } 304 305 Debug().write(Lvl.ERROR, this, 307 "Couldn't find table source - resource name: " + 308 table_str + " table_id: " + table_id); 309 310 return null; 311 } 312 313 319 private static String createEncodedTableFile(MasterTableDataSource table) { 320 char type; 321 if (table instanceof V1MasterTableDataSource) { 322 type = '1'; 323 } 324 else if (table instanceof V2MasterTableDataSource) { 325 type = '2'; 326 } 327 else { 328 throw new RuntimeException ("Unrecognised MasterTableDataSource class."); 329 } 330 StringBuffer buf = new StringBuffer (); 331 buf.append(':'); 332 buf.append(type); 333 buf.append(table.getSourceIdent()); 334 return new String (buf); 335 } 336 337 343 private void readVisibleTables() throws IOException { 344 345 StateResource[] tables = state_store.getVisibleList(); 347 for (int i = 0; i < tables.length; ++i) { 349 StateResource resource = tables[i]; 350 351 int master_table_id = (int) resource.table_id; 352 String file_name = resource.name; 353 354 int table_type = 1; 356 if (file_name.startsWith(":")) { 357 if (file_name.charAt(1) == '1') { 358 table_type = 1; 359 } 360 else if (file_name.charAt(1) == '2') { 361 table_type = 2; 362 } 363 else { 364 throw new RuntimeException ("Table type is not known."); 365 } 366 file_name = file_name.substring(2); 367 } 368 369 MasterTableDataSource master = 371 loadMasterTable(master_table_id, file_name, table_type); 372 373 if (master == null) { 374 throw new Error ("Table file for " + file_name + " was not found."); 375 } 376 377 if (master instanceof V1MasterTableDataSource) { 378 V1MasterTableDataSource v1_master = (V1MasterTableDataSource) master; 379 v1_master.open(file_name); 380 } 381 else if (master instanceof V2MasterTableDataSource) { 382 V2MasterTableDataSource v2_master = (V2MasterTableDataSource) master; 383 v2_master.open(file_name); 384 } 385 else { 386 throw new Error ("Unknown master table type: " + master.getClass()); 387 } 388 389 table_list.add(master); 391 392 } 393 394 } 395 396 402 public void checkVisibleTables(UserTerminal terminal) throws IOException { 403 404 StateResource[] tables = state_store.getVisibleList(); 406 for (int i = 0; i < tables.length; ++i) { 408 StateResource resource = tables[i]; 409 410 int master_table_id = (int) resource.table_id; 411 String file_name = resource.name; 412 413 int table_type = 1; 415 if (file_name.startsWith(":")) { 416 if (file_name.charAt(1) == '1') { 417 table_type = 1; 418 } 419 else if (file_name.charAt(1) == '2') { 420 table_type = 2; 421 } 422 else { 423 throw new RuntimeException ("Table type is not known."); 424 } 425 file_name = file_name.substring(2); 426 } 427 428 MasterTableDataSource master = 430 loadMasterTable(master_table_id, file_name, table_type); 431 432 if (master instanceof V1MasterTableDataSource) { 433 V1MasterTableDataSource v1_master = (V1MasterTableDataSource) master; 434 v1_master.checkAndRepair(file_name, terminal); 435 } 436 else if (master instanceof V2MasterTableDataSource) { 437 V2MasterTableDataSource v2_master = (V2MasterTableDataSource) master; 438 v2_master.checkAndRepair(file_name, terminal); 439 } 440 else { 441 throw new Error ("Unknown master table type: " + master.getClass()); 442 } 443 444 table_list.add(master); 446 447 store_system.setCheckPoint(); 449 450 } 451 452 } 453 454 455 456 457 458 459 460 461 470 private void readDroppedTables() throws IOException { 471 472 StateResource[] tables = state_store.getDeleteList(); 474 for (int i = 0; i < tables.length; ++i) { 476 StateResource resource = tables[i]; 477 478 int master_table_id = (int) resource.table_id; 479 String file_name = resource.name; 480 481 int table_type = 1; 483 if (file_name.startsWith(":")) { 484 if (file_name.charAt(1) == '1') { 485 table_type = 1; 486 } 487 else if (file_name.charAt(1) == '2') { 488 table_type = 2; 489 } 490 else { 491 throw new RuntimeException ("Table type is not known."); 492 } 493 file_name = file_name.substring(2); 494 } 495 496 MasterTableDataSource master = 498 loadMasterTable(master_table_id, file_name, table_type); 499 500 if (master == null) { 502 state_store.removeDeleteResource(resource.name); 503 } 504 else { 505 if (master instanceof V1MasterTableDataSource) { 506 V1MasterTableDataSource v1_master = (V1MasterTableDataSource) master; 507 v1_master.open(file_name); 508 } 509 else if (master instanceof V2MasterTableDataSource) { 510 V2MasterTableDataSource v2_master = (V2MasterTableDataSource) master; 511 v2_master.open(file_name); 512 } 513 else { 514 throw new Error ("Unknown master table type: " + master.getClass()); 515 } 516 517 table_list.add(master); 519 } 520 521 } 522 523 state_store.commit(); 525 526 } 527 528 645 void updateSystemTableSchema() { 646 Transaction transaction = createTransaction(); 648 649 DataTableDef table; 650 651 table = new DataTableDef(); 652 table.setTableName(SYS_SEQUENCE_INFO); 653 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 654 table.addColumn(DataTableColumnDef.createStringColumn("schema")); 655 table.addColumn(DataTableColumnDef.createStringColumn("name")); 656 table.addColumn(DataTableColumnDef.createNumericColumn("type")); 657 transaction.alterCreateTable(table, 187, 128); 658 659 table = new DataTableDef(); 660 table.setTableName(SYS_SEQUENCE); 661 table.addColumn(DataTableColumnDef.createNumericColumn("seq_id")); 662 table.addColumn(DataTableColumnDef.createNumericColumn("last_value")); 663 table.addColumn(DataTableColumnDef.createNumericColumn("increment")); 664 table.addColumn(DataTableColumnDef.createNumericColumn("minvalue")); 665 table.addColumn(DataTableColumnDef.createNumericColumn("maxvalue")); 666 table.addColumn(DataTableColumnDef.createNumericColumn("start")); 667 table.addColumn(DataTableColumnDef.createNumericColumn("cache")); 668 table.addColumn(DataTableColumnDef.createBooleanColumn("cycle")); 669 transaction.alterCreateTable(table, 187, 128); 670 671 table = new DataTableDef(); 672 table.setTableName(PRIMARY_INFO_TABLE); 673 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 674 table.addColumn(DataTableColumnDef.createStringColumn("name")); 675 table.addColumn(DataTableColumnDef.createStringColumn("schema")); 676 table.addColumn(DataTableColumnDef.createStringColumn("table")); 677 table.addColumn(DataTableColumnDef.createNumericColumn("deferred")); 678 transaction.alterCreateTable(table, 187, 128); 679 680 table = new DataTableDef(); 681 table.setTableName(FOREIGN_INFO_TABLE); 682 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 683 table.addColumn(DataTableColumnDef.createStringColumn("name")); 684 table.addColumn(DataTableColumnDef.createStringColumn("schema")); 685 table.addColumn(DataTableColumnDef.createStringColumn("table")); 686 table.addColumn(DataTableColumnDef.createStringColumn("ref_schema")); 687 table.addColumn(DataTableColumnDef.createStringColumn("ref_table")); 688 table.addColumn(DataTableColumnDef.createStringColumn("update_rule")); 689 table.addColumn(DataTableColumnDef.createStringColumn("delete_rule")); 690 table.addColumn(DataTableColumnDef.createNumericColumn("deferred")); 691 transaction.alterCreateTable(table, 187, 128); 692 693 table = new DataTableDef(); 694 table.setTableName(UNIQUE_INFO_TABLE); 695 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 696 table.addColumn(DataTableColumnDef.createStringColumn("name")); 697 table.addColumn(DataTableColumnDef.createStringColumn("schema")); 698 table.addColumn(DataTableColumnDef.createStringColumn("table")); 699 table.addColumn(DataTableColumnDef.createNumericColumn("deferred")); 700 transaction.alterCreateTable(table, 187, 128); 701 702 table = new DataTableDef(); 703 table.setTableName(CHECK_INFO_TABLE); 704 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 705 table.addColumn(DataTableColumnDef.createStringColumn("name")); 706 table.addColumn(DataTableColumnDef.createStringColumn("schema")); 707 table.addColumn(DataTableColumnDef.createStringColumn("table")); 708 table.addColumn(DataTableColumnDef.createStringColumn("expression")); 709 table.addColumn(DataTableColumnDef.createNumericColumn("deferred")); 710 table.addColumn( 711 DataTableColumnDef.createBinaryColumn("serialized_expression")); 712 transaction.alterCreateTable(table, 187, 128); 713 714 table = new DataTableDef(); 715 table.setTableName(PRIMARY_COLS_TABLE); 716 table.addColumn(DataTableColumnDef.createNumericColumn("pk_id")); 717 table.addColumn(DataTableColumnDef.createStringColumn("column")); 718 table.addColumn(DataTableColumnDef.createNumericColumn("seq_no")); 719 transaction.alterCreateTable(table, 91, 128); 720 721 table = new DataTableDef(); 722 table.setTableName(UNIQUE_COLS_TABLE); 723 table.addColumn(DataTableColumnDef.createNumericColumn("un_id")); 724 table.addColumn(DataTableColumnDef.createStringColumn("column")); 725 table.addColumn(DataTableColumnDef.createNumericColumn("seq_no")); 726 transaction.alterCreateTable(table, 91, 128); 727 728 table = new DataTableDef(); 729 table.setTableName(FOREIGN_COLS_TABLE); 730 table.addColumn(DataTableColumnDef.createNumericColumn("fk_id")); 731 table.addColumn(DataTableColumnDef.createStringColumn("fcolumn")); 732 table.addColumn(DataTableColumnDef.createStringColumn("pcolumn")); 733 table.addColumn(DataTableColumnDef.createNumericColumn("seq_no")); 734 transaction.alterCreateTable(table, 91, 128); 735 736 table = new DataTableDef(); 737 table.setTableName(SCHEMA_INFO_TABLE); 738 table.addColumn(DataTableColumnDef.createNumericColumn("id")); 739 table.addColumn(DataTableColumnDef.createStringColumn("name")); 740 table.addColumn(DataTableColumnDef.createStringColumn("type")); 741 table.addColumn(DataTableColumnDef.createStringColumn("other")); 742 transaction.alterCreateTable(table, 91, 128); 743 744 table = new DataTableDef(); 746 table.setTableName(PERSISTENT_VAR_TABLE); 747 table.addColumn(DataTableColumnDef.createStringColumn("variable")); 748 table.addColumn(DataTableColumnDef.createStringColumn("value")); 749 transaction.alterCreateTable(table, 91, 128); 750 751 try { 753 transaction.closeAndCommit(); 754 } 755 catch (TransactionException e) { 756 Debug().writeException(e); 757 throw new Error ("Transaction Exception creating conglomerate."); 758 } 759 760 } 761 762 766 void resetTableID(TableName tname) { 767 Transaction transaction = createTransaction(); 769 MutableTableDataSource table = transaction.getTable(tname); 771 DataTableDef table_def = table.getDataTableDef(); 773 int col_index = table_def.findColumnName("id"); 774 if (col_index == -1) { 775 throw new Error ("Column name 'id' not found."); 776 } 777 SelectableScheme scheme = table.getColumnScheme(col_index); 779 IntegerVector ivec = scheme.selectLast(); 780 if (ivec.size() > 0) { 781 TObject ob = table.getCellContents(col_index, ivec.intAt(0)); 782 BigNumber b_num = ob.toBigNumber(); 783 if (b_num != null) { 784 transaction.setUniqueID(tname, b_num.longValue() + 1L); 786 } 787 } 788 789 try { 791 transaction.closeAndCommit(); 792 } 793 catch (TransactionException e) { 794 Debug().writeException(e); 795 throw new Error ("Transaction Exception creating conglomerate."); 796 } 797 } 798 799 803 void resetAllSystemTableID() { 804 resetTableID(PRIMARY_INFO_TABLE); 805 resetTableID(FOREIGN_INFO_TABLE); 806 resetTableID(UNIQUE_INFO_TABLE); 807 resetTableID(CHECK_INFO_TABLE); 808 resetTableID(SCHEMA_INFO_TABLE); 809 } 810 811 816 private void initializeSystemTableSchema() { 817 Transaction transaction = createTransaction(); 819 820 transaction.createSchema(SYSTEM_SCHEMA, "SYSTEM"); 822 823 final String [] id_col = new String [] { "id" }; 826 transaction.addPrimaryKeyConstraint(PRIMARY_INFO_TABLE, 827 id_col, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_PK_PK"); 828 transaction.addPrimaryKeyConstraint(FOREIGN_INFO_TABLE, 829 id_col, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_FK_PK"); 830 transaction.addPrimaryKeyConstraint(UNIQUE_INFO_TABLE, 831 id_col, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_UNIQUE_PK"); 832 transaction.addPrimaryKeyConstraint(CHECK_INFO_TABLE, 833 id_col, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_CHECK_PK"); 834 transaction.addPrimaryKeyConstraint(SCHEMA_INFO_TABLE, 835 id_col, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_SCHEMA_PK"); 836 837 final String [] fk_col = new String [1]; 840 final String [] fk_ref_col = new String [] { "id" }; 841 fk_col[0] = "pk_id"; 842 transaction.addForeignKeyConstraint( 843 PRIMARY_COLS_TABLE, fk_col, PRIMARY_INFO_TABLE, fk_ref_col, 844 Transaction.NO_ACTION, Transaction.NO_ACTION, 845 Transaction.INITIALLY_IMMEDIATE, "SYSTEM_PK_FK"); 846 fk_col[0] = "fk_id"; 847 transaction.addForeignKeyConstraint( 848 FOREIGN_COLS_TABLE, fk_col, FOREIGN_INFO_TABLE, fk_ref_col, 849 Transaction.NO_ACTION, Transaction.NO_ACTION, 850 Transaction.INITIALLY_IMMEDIATE, "SYSTEM_FK_FK"); 851 fk_col[0] = "un_id"; 852 transaction.addForeignKeyConstraint( 853 UNIQUE_COLS_TABLE, fk_col, UNIQUE_INFO_TABLE, fk_ref_col, 854 Transaction.NO_ACTION, Transaction.NO_ACTION, 855 Transaction.INITIALLY_IMMEDIATE, "SYSTEM_UNIQUE_FK"); 856 857 String [] columns = new String [] { "schema", "table" }; 860 transaction.addUniqueConstraint(PRIMARY_INFO_TABLE, 861 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_PKEY_ST_UNIQUE"); 862 columns = new String [] { "name" }; 864 transaction.addUniqueConstraint(SCHEMA_INFO_TABLE, 865 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_SCHEMA_UNIQUE"); 866 columns = new String [] { "name", "schema" }; 868 transaction.addUniqueConstraint(PRIMARY_INFO_TABLE, 870 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_PKEY_UNIQUE"); 871 transaction.addUniqueConstraint(FOREIGN_INFO_TABLE, 873 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_FKEY_UNIQUE"); 874 transaction.addUniqueConstraint(UNIQUE_INFO_TABLE, 876 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_UNIQUE_UNIQUE"); 877 transaction.addUniqueConstraint(CHECK_INFO_TABLE, 879 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_CHECK_UNIQUE"); 880 881 columns = new String [] { "variable" }; 883 transaction.addUniqueConstraint(PERSISTENT_VAR_TABLE, 884 columns, Transaction.INITIALLY_IMMEDIATE, "SYSTEM_DATABASEVARS_UNIQUE"); 885 886 transaction.setPersistentVar("database.version", "1.4"); 888 889 try { 891 transaction.closeAndCommit(); 892 } 893 catch (TransactionException e) { 894 Debug().writeException(e); 895 throw new Error ("Transaction Exception initializing conglomerate."); 896 } 897 898 } 899 900 904 private void initializeBlobStore() throws IOException { 905 906 boolean blob_store_exists = storeSystem().storeExists("BlobStore"); 908 if (!blob_store_exists && isReadOnly()) { 911 return; 912 } 913 914 if (blob_store_exists) { 916 act_blob_store = storeSystem().openStore("BlobStore"); 917 } 918 else { 919 act_blob_store = storeSystem().createStore("BlobStore"); 920 } 921 922 try { 923 act_blob_store.lockForWrite(); 924 925 blob_store = new BlobStore(act_blob_store); 927 928 MutableArea fixed_area = act_blob_store.getMutableArea(-1); 930 if (!blob_store_exists) { 932 long header_p = blob_store.create(); 933 fixed_area.putLong(header_p); 934 fixed_area.checkOut(); 935 } 936 else { 937 long header_p = fixed_area.getLong(); 939 blob_store.init(header_p); 940 } 941 } 942 finally { 943 act_blob_store.unlockForWrite(); 944 } 945 946 } 947 948 949 950 951 952 953 954 955 956 958 961 private boolean isReadOnly() { 962 return system.readOnlyAccess(); 963 } 964 965 968 private File getPath() { 969 return system.getDatabasePath(); 970 } 971 972 976 private int nextUniqueTableID() throws IOException { 977 return state_store.nextTableID(); 978 } 979 980 981 984 private void setupInternal() { 985 commit_id = 0; 986 table_list = new ArrayList (); 987 988 999 } 1000 1001 1003 1010 void minimalCreate(String name) throws IOException { 1011 this.name = name; 1012 1013 if (exists(name)) { 1014 throw new IOException("Conglomerate already exists: " + name); 1015 } 1016 1017 if (!isReadOnly()) { 1020 storeSystem().lock(name); 1021 } 1022 1023 act_state_store = storeSystem().createStore(name + STATE_POST); 1025 try { 1026 act_state_store.lockForWrite(); 1027 1028 state_store = new StateStore(act_state_store); 1029 long head_p = state_store.create(); 1030 MutableArea fixed_area = act_state_store.getMutableArea(-1); 1032 fixed_area.putLong(head_p); 1033 fixed_area.checkOut(); 1034 } 1035 finally { 1036 act_state_store.unlockForWrite(); 1037 } 1038 1039 setupInternal(); 1040 1041 initializeBlobStore(); 1043 1044 updateSystemTableSchema(); 1046 1047 } 1048 1049 1054 public void create(String name) throws IOException { 1055 minimalCreate(name); 1056 1057 initializeSystemTableSchema(); 1059 1060 state_store.commit(); 1062 1063 } 1064 1065 1070 public void open(String name) throws IOException { 1071 this.name = name; 1072 1073 if (!exists(name)) { 1074 throw new IOException("Conglomerate doesn't exists: " + name); 1075 } 1076 1077 if (!isReadOnly()) { 1079 storeSystem().lock(name); 1081 } 1082 1083 act_state_store = storeSystem().openStore(name + STATE_POST); 1085 state_store = new StateStore(act_state_store); 1086 Area fixed_area = act_state_store.getArea(-1); 1088 long head_p = fixed_area.getLong(); 1089 state_store.init(head_p); 1090 1091 setupInternal(); 1092 1093 initializeBlobStore(); 1095 1096 readVisibleTables(); 1097 readDroppedTables(); 1098 1099 cleanUpConglomerate(); 1101 1102 } 1103 1104 1108 public void close() throws IOException { 1109 synchronized (commit_lock) { 1110 1111 cleanUpConglomerate(); 1113 1114 store_system.setCheckPoint(); 1116 1117 int size = table_list.size(); 1119 for (int i = 0; i < size; ++i) { 1120 MasterTableDataSource master = 1121 (MasterTableDataSource) table_list.get(i); 1122 master.dispose(false); 1123 } 1124 1125 state_store.commit(); 1126 storeSystem().closeStore(act_state_store); 1127 1128 table_list = null; 1129 1130 } 1131 1132 storeSystem().unlock(name); 1134 1135 if (blob_store != null) { 1136 storeSystem().closeStore(act_blob_store); 1137 } 1138 1139 } 1141 1142 1163 1170 public void delete() throws IOException { 1171 synchronized (commit_lock) { 1172 1173 cleanUpConglomerate(); 1175 1176 int size = table_list.size(); 1178 for (int i = 0; i < size; ++i) { 1179 MasterTableDataSource master = 1180 (MasterTableDataSource) table_list.get(i); 1181 master.drop(); 1182 } 1183 1184 state_store.commit(); 1186 storeSystem().closeStore(act_state_store); 1187 storeSystem().deleteStore(act_state_store); 1188 1189 if (blob_store != null) { 1191 storeSystem().closeStore(act_blob_store); 1192 storeSystem().deleteStore(act_blob_store); 1193 } 1194 1195 table_list = null; 1197 1198 } 1199 1200 storeSystem().unlock(name); 1202 } 1203 1204 1207 public boolean isClosed() { 1208 synchronized (commit_lock) { 1209 return table_list == null; 1210 } 1211 } 1212 1213 1214 1218 public boolean exists(String name) throws IOException { 1219 return storeSystem().storeExists(name + STATE_POST); 1220 } 1221 1222 1233 public void liveCopyTo(TableDataConglomerate dest_conglomerate) 1234 throws IOException { 1235 1236 StoreSystem dest_store_system = dest_conglomerate.storeSystem(); 1238 1239 dest_conglomerate.blob_store.copyFrom(dest_store_system, blob_store); 1242 1243 Transaction transaction = createTransaction(); 1245 1246 try { 1247 1248 transaction.liveCopyAllDataTo(dest_conglomerate); 1250 1251 } 1252 finally { 1253 try { 1255 transaction.closeAndCommit(); 1256 } 1257 catch (TransactionException e) { 1258 throw new RuntimeException ("Transaction Error: " + e.getMessage()); 1259 } 1260 } 1261 1262 getSystem().stats().increment("TableDataConglomerate.liveCopies"); 1264 1265 } 1266 1267 1269 1273 public RawDiagnosticTable getDiagnosticTable(String table_file_name) { 1274 synchronized (commit_lock) { 1275 for (int i = 0; i < table_list.size(); ++i) { 1276 MasterTableDataSource master = 1277 (MasterTableDataSource) table_list.get(i); 1278 if (master.getSourceIdent().equals(table_file_name)) { 1279 return master.getRawDiagnosticTable(); 1280 } 1281 } 1282 } 1283 return null; 1284 } 1285 1286 1289 public String [] getAllTableFileNames() { 1290 synchronized (commit_lock) { 1291 String [] list = new String [table_list.size()]; 1292 for (int i = 0; i < table_list.size(); ++i) { 1293 MasterTableDataSource master = 1294 (MasterTableDataSource) table_list.get(i); 1295 list[i] = master.getSourceIdent(); 1296 } 1297 return list; 1298 } 1299 } 1300 1301 1303 1331 public void addTransactionModificationListener(TableName table_name, 1332 TransactionModificationListener listener) { 1333 synchronized (modification_listeners) { 1334 ArrayList list = (ArrayList ) modification_listeners.get(table_name); 1335 if (list == null) { 1336 list = new ArrayList (); 1339 modification_listeners.put(table_name, list); 1340 } 1341 1342 list.add(listener); 1343 } 1344 } 1345 1346 1355 public void removeTransactionModificationListener(TableName table_name, 1356 TransactionModificationListener listener) { 1357 synchronized (modification_listeners) { 1358 ArrayList list = (ArrayList ) modification_listeners.get(table_name); 1359 if (list != null) { 1360 int sz = list.size(); 1361 for (int i = sz - 1; i >= 0; --i) { 1362 if (list.get(i) == listener) { 1363 list.remove(i); 1364 } 1365 } 1366 } 1367 } 1368 } 1369 1370 1372 1378 public Transaction createTransaction() { 1379 long this_commit_id; 1380 ArrayList this_committed_tables = new ArrayList (); 1381 1382 synchronized (commit_lock) { 1384 1385 this_commit_id = commit_id; 1386 StateResource[] committed_table_list = state_store.getVisibleList(); 1387 for (int i = 0; i < committed_table_list.length; ++i) { 1388 this_committed_tables.add( 1389 getMasterTable((int) committed_table_list[i].table_id)); 1390 } 1391 1392 int sz = this_committed_tables.size(); 1394 ArrayList index_info = new ArrayList (sz); 1395 for (int i = 0; i < sz; ++i) { 1396 MasterTableDataSource mtable = 1397 (MasterTableDataSource) this_committed_tables.get(i); 1398 index_info.add(mtable.createIndexSet()); 1399 } 1400 1401 Transaction t = new Transaction(this, 1403 this_commit_id, this_committed_tables, index_info); 1404 open_transactions.addTransaction(t); 1405 return t; 1406 1407 } 1408 1409 } 1410 1411 1419 private void closeTransaction(Transaction transaction) { 1420 boolean last_transaction = false; 1421 synchronized (commit_lock) { 1423 open_transactions.removeTransaction(transaction); 1424 ++commit_id; 1426 last_transaction = open_transactions.count() == 0; 1428 } 1429 1430 if (last_transaction) { 1432 try { 1433 cleanUpConglomerate(); 1434 } 1435 catch (IOException e) { 1436 Debug().write(Lvl.ERROR, this, "Error cleaning up conglomerate"); 1437 Debug().writeException(Lvl.ERROR, e); 1438 } 1439 } 1440 1441 } 1442 1443 1444 1454 private boolean closeAndDropTable(String table_file_name) throws IOException { 1455 for (int i = 0; i < table_list.size(); ++i) { 1457 MasterTableDataSource t = (MasterTableDataSource) table_list.get(i); 1458 String enc_fn = table_file_name.substring(2); 1459 if (t.getSourceIdent().equals(enc_fn)) { 1460 if (t.isRootLocked()) { 1462 return false; 1464 } 1465 1466 boolean b = t.drop(); 1468 if (b) { 1469 table_list.remove(i); 1470 } 1471 return b; 1472 } 1473 } 1474 return false; 1475 } 1476 1477 1484 private void closeTable(String table_file_name, boolean pending_drop) 1485 throws IOException { 1486 for (int i = 0; i < table_list.size(); ++i) { 1488 MasterTableDataSource t = (MasterTableDataSource) table_list.get(i); 1489 String enc_fn = table_file_name.substring(2); 1490 if (t.getSourceIdent().equals(enc_fn)) { 1491 if (t.isRootLocked()) { 1493 return; 1495 } 1496 1497 t.dispose(pending_drop); 1499 return; 1500 } 1501 } 1502 return; 1503 } 1504 1505 1510 private void cleanUpConglomerate() throws IOException { 1511 synchronized (commit_lock) { 1512 if (isClosed()) { 1513 return; 1514 } 1515 1516 if (open_transactions.count() == 0) { 1518 1519 StateResource[] delete_list = state_store.getDeleteList(); 1520 if (delete_list.length > 0) { 1521 int drop_count = 0; 1522 1523 for (int i = delete_list.length - 1; i >= 0; --i) { 1524 String fn = (String ) delete_list[i].name; 1525 closeTable(fn, true); 1526 } 1527 1528 1544 for (int i = delete_list.length - 1; i >= 0; --i) { 1545 String fn = (String ) delete_list[i].name; 1546 boolean dropped = closeAndDropTable(fn); 1547 if (dropped) { 1549 state_store.removeDeleteResource(fn); 1550 ++drop_count; 1551 } 1552 } 1553 1554 if (drop_count > 0) { 1556 state_store.commit(); 1557 } 1558 } 1559 1560 } 1561 } 1562 } 1563 1564 1566 1570 private static class TableRowVariableResolver implements VariableResolver { 1571 1572 private TableDataSource table; 1573 private int row_index = -1; 1574 1575 public TableRowVariableResolver(TableDataSource table, int row) { 1576 this.table = table; 1577 this.row_index = row; 1578 } 1579 1580 private int findColumnName(Variable variable) { 1581 int col_index = table.getDataTableDef().findColumnName( 1582 variable.getName()); 1583 if (col_index == -1) { 1584 throw new Error ("Can't find column: " + variable); 1585 } 1586 return col_index; 1587 } 1588 1589 1591 public int setID() { 1592 return row_index; 1593 } 1594 1595 public TObject resolve(Variable variable) { 1596 int col_index = findColumnName(variable); 1597 return table.getCellContents(col_index, row_index); 1598 } 1599 1600 public TType returnTType(Variable variable) { 1601 int col_index = findColumnName(variable); 1602 return table.getDataTableDef().columnAt(col_index).getTType(); 1603 } 1604 1605 } 1606 1607 1611 static String stringColumnList(String [] list) { 1612 StringBuffer buf = new StringBuffer (); 1613 for (int i = 0; i < list.length - 1; ++i) { 1614 buf.append(list[i]); 1615 } 1616 buf.append(list[list.length - 1]); 1617 return new String (buf); 1618 } 1619 1620 1624 static String deferredString(short deferred) { 1625 switch(deferred) { 1626 case(Transaction.INITIALLY_IMMEDIATE): 1627 return "Immediate"; 1628 case(Transaction.INITIALLY_DEFERRED): 1629 return "Deferred"; 1630 default: 1631 throw new Error ("Unknown deferred string."); 1632 } 1633 } 1634 1635 1639 static int[] findColumnIndices(DataTableDef table_def, String [] cols) { 1640 int[] col_indexes = new int[cols.length]; 1642 for (int i = 0; i < cols.length; ++i) { 1643 col_indexes[i] = table_def.findColumnName(cols[i]); 1644 } 1645 return col_indexes; 1646 } 1647 1648 1654 private static boolean isUniqueColumns( 1655 TableDataSource table, int rindex, String [] cols, 1656 boolean nulls_are_allowed) { 1657 1658 DataTableDef table_def = table.getDataTableDef(); 1659 IntegerVector identical_rows = null; 1661 1662 int[] col_indexes = findColumnIndices(table_def, cols); 1664 1665 for (int i = 0; i < col_indexes.length; ++i) { 1668 TObject cell = table.getCellContents(col_indexes[i], rindex); 1669 if (cell.isNull()) { 1670 return nulls_are_allowed; 1671 } 1672 } 1673 1674 1675 for (int i = 0; i < col_indexes.length; ++i) { 1676 1677 int col_index = col_indexes[i]; 1678 1679 TObject cell = table.getCellContents(col_index, rindex); 1682 1683 1688 if (identical_rows == null || identical_rows.size() > 0) { 1689 1690 1693 SelectableScheme ss = table.getColumnScheme(col_index); 1694 IntegerVector ivec = ss.selectEqual(cell); 1695 1696 1704 if (identical_rows == null) { 1705 identical_rows = ivec; 1706 } 1707 else { 1708 ivec.quickSort(); 1709 int row_index = identical_rows.size() - 1; 1710 while (row_index >= 0) { 1711 int val = identical_rows.intAt(row_index); 1712 int found_index = ivec.sortedIndexOf(val); 1713 if (found_index >= ivec.size() || 1715 ivec.intAt(found_index) != val) { 1716 identical_rows.removeIntAt(row_index); 1717 } 1718 --row_index; 1719 } 1720 } 1721 1722 } 1723 1724 } 1726 if (identical_rows != null) { 1729 int sz = identical_rows.size(); 1730 if (sz == 1) { 1731 return true; 1732 } 1733 if (sz > 1) { 1734 return false; 1735 } 1736 else if (sz == 0) { 1737 throw new Error ("Assertion failed: We must be able to find the " + 1738 "row we are testing uniqueness against!"); 1739 } 1740 } 1741 return true; 1742 1743 } 1744 1745 1746 1752 static IntegerVector findKeys(TableDataSource t2, int[] col2_indexes, 1753 TObject[] key_value) { 1754 1755 int key_size = key_value.length; 1756 SelectableScheme ss = t2.getColumnScheme(col2_indexes[0]); 1759 IntegerVector list = ss.selectEqual(key_value[0]); 1760 if (key_size > 1) { 1761 int sz = list.size(); 1763 for (int i = sz - 1; i >= 0; --i) { 1765 int r_index = list.intAt(i); 1766 for (int c = 1; c < key_size; ++c) { 1768 int col_index = col2_indexes[c]; 1769 TObject c_value = key_value[c]; 1770 if (c_value.compareTo(t2.getCellContents(col_index, r_index)) != 0) { 1771 list.removeIntAt(i); 1774 break; 1776 } 1777 } 1778 } 1779 } 1780 1781 return list; 1782 } 1783 1784 1796 private static int rowCountOfReferenceTable( 1797 SimpleTransaction transaction, 1798 int row_index, TableName table1, String [] cols1, 1799 TableName table2, String [] cols2, 1800 boolean check_source_table_key) { 1801 1802 TableDataSource t1 = transaction.getTableDataSource(table1); 1804 TableDataSource t2 = transaction.getTableDataSource(table2); 1805 DataTableDef dtd1 = t1.getDataTableDef(); 1807 DataTableDef dtd2 = t2.getDataTableDef(); 1808 int[] col1_indexes = findColumnIndices(dtd1, cols1); 1810 int[] col2_indexes = findColumnIndices(dtd2, cols2); 1811 1812 int key_size = col1_indexes.length; 1813 TObject[] key_value = new TObject[key_size]; 1815 int null_count = 0; 1816 for (int n = 0; n < key_size; ++n) { 1817 key_value[n] = t1.getCellContents(col1_indexes[n], row_index); 1818 if (key_value[n].isNull()) { 1819 ++null_count; 1820 } 1821 } 1822 1823 if (null_count > 0) { 1825 return -1; 1826 } 1827 1828 if (check_source_table_key) { 1833 IntegerVector keys = findKeys(t1, col1_indexes, key_value); 1834 int key_count = keys.size(); 1835 if (key_count > 0) { 1836 return 0; 1837 } 1838 } 1839 1840 return findKeys(t2, col2_indexes, key_value).size(); 1841 } 1842 1843 1844 1848 static void checkFieldConstraintViolations( 1849 SimpleTransaction transaction, 1850 TableDataSource table, int[] row_indices) { 1851 1852 if (row_indices == null || row_indices.length == 0) { 1854 return; 1855 } 1856 1857 1861 DataTableDef table_def = table.getDataTableDef(); 1862 TableName table_name = table_def.getTableName(); 1863 1864 1868 int len = table_def.columnCount(); 1870 for (int i = 0; i < len; ++i) { 1871 1872 DataTableColumnDef column_def = table_def.columnAt(i); 1874 for (int rn = 0; rn < row_indices.length; ++rn) { 1876 TObject cell = table.getCellContents(i, row_indices[rn]); 1877 1878 if (column_def.isNotNull() && cell.isNull()) { 1881 throw new DatabaseConstraintViolationException( 1882 DatabaseConstraintViolationException.NULLABLE_VIOLATION, 1883 "You tried to add 'null' cell to column '" + 1884 table_def.columnAt(i).getName() + 1885 "' which is declared as 'not_null'"); 1886 } 1887 1888 if (!cell.isNull() && 1891 column_def.getSQLType() == 1892 com.mckoi.database.global.SQLTypes.JAVA_OBJECT) { 1893 String class_constraint = column_def.getClassConstraint(); 1894 if (!class_constraint.equals("java.lang.Object")) { 1897 ByteLongObject serialized_jobject = 1899 (ByteLongObject) cell.getObject(); 1900 Object ob = ObjectTranslator.deserialize(serialized_jobject); 1902 if (!ob.getClass().isAssignableFrom( 1904 column_def.getClassConstraintAsClass())) { 1905 throw new DatabaseConstraintViolationException( 1906 DatabaseConstraintViolationException.JAVA_TYPE_VIOLATION, 1907 "The Java object being inserted is not derived from the " + 1908 "class constraint defined for the column (" + 1909 class_constraint + ")"); 1910 } 1911 } 1912 } 1913 1914 } 1916 } 1918 } 1919 1920 1935 static void checkAddConstraintViolations( 1936 SimpleTransaction transaction, 1937 TableDataSource table, int[] row_indices, short deferred) { 1938 1939 String cur_schema = table.getDataTableDef().getSchema(); 1940 QueryContext context = new SystemQueryContext(transaction, cur_schema); 1941 1942 if (row_indices == null || row_indices.length == 0) { 1944 return; 1945 } 1946 1947 DataTableDef table_def = table.getDataTableDef(); 1948 TableName table_name = table_def.getTableName(); 1949 1950 1952 Transaction.ColumnGroup primary_key = 1954 Transaction.queryTablePrimaryKeyGroup(transaction, table_name); 1955 if (primary_key != null && 1956 (deferred == Transaction.INITIALLY_DEFERRED || 1957 primary_key.deferred == Transaction.INITIALLY_IMMEDIATE)) { 1958 1959 for (int rn = 0; rn < row_indices.length; ++rn) { 1961 if (!isUniqueColumns(table, row_indices[rn], 1962 primary_key.columns, false)) { 1963 throw new DatabaseConstraintViolationException( 1964 DatabaseConstraintViolationException.PRIMARY_KEY_VIOLATION, 1965 deferredString(deferred) + " primary Key constraint violation (" + 1966 primary_key.name + ") Columns = ( " + 1967 stringColumnList(primary_key.columns) + 1968 " ) Table = ( " + table_name.toString() + " )"); 1969 } 1970 } 1972 } 1973 1974 Transaction.ColumnGroup[] unique_constraints = 1976 Transaction.queryTableUniqueGroups(transaction, table_name); 1977 for (int i = 0; i < unique_constraints.length; ++i) { 1978 Transaction.ColumnGroup unique = unique_constraints[i]; 1979 if (deferred == Transaction.INITIALLY_DEFERRED || 1980 unique.deferred == Transaction.INITIALLY_IMMEDIATE) { 1981 1982 for (int rn = 0; rn < row_indices.length; ++rn) { 1984 if (!isUniqueColumns(table, row_indices[rn], unique.columns, true)) { 1985 throw new DatabaseConstraintViolationException( 1986 DatabaseConstraintViolationException.UNIQUE_VIOLATION, 1987 deferredString(deferred) + " unique constraint violation (" + 1988 unique.name + ") Columns = ( " + 1989 stringColumnList(unique.columns) + " ) Table = ( " + 1990 table_name.toString() + " )"); 1991 } 1992 } 1994 } 1995 } 1996 1997 Transaction.ColumnGroupReference[] foreign_constraints = 2001 Transaction.queryTableForeignKeyReferences(transaction, table_name); 2002 for (int i = 0; i < foreign_constraints.length; ++i) { 2003 Transaction.ColumnGroupReference ref = foreign_constraints[i]; 2004 if (deferred == Transaction.INITIALLY_DEFERRED || 2005 ref.deferred == Transaction.INITIALLY_IMMEDIATE) { 2006 for (int rn = 0; rn < row_indices.length; ++rn) { 2008 2010 int row_count = rowCountOfReferenceTable(transaction, 2014 row_indices[rn], 2015 ref.key_table_name, ref.key_columns, 2016 ref.ref_table_name, ref.ref_columns, 2017 false); 2018 if (row_count == -1) { 2019 } 2021 if (row_count == 0) { 2022 throw new DatabaseConstraintViolationException( 2023 DatabaseConstraintViolationException.FOREIGN_KEY_VIOLATION, 2024 deferredString(deferred)+" foreign key constraint violation (" + 2025 ref.name + ") Columns = " + 2026 ref.key_table_name.toString() + "( " + 2027 stringColumnList(ref.key_columns) + " ) -> " + 2028 ref.ref_table_name.toString() + "( " + 2029 stringColumnList(ref.ref_columns) + " )"); 2030 } 2031 } } 2033 } 2034 2035 Transaction.CheckExpression[] check_constraints = 2037 Transaction.queryTableCheckExpressions(transaction, table_name); 2038 2039 TransactionSystem system = transaction.getSystem(); 2041 2042 for (int i = 0; i < check_constraints.length; ++i) { 2044 Transaction.CheckExpression check = check_constraints[i]; 2045 if (deferred == Transaction.INITIALLY_DEFERRED || 2046 check.deferred == Transaction.INITIALLY_IMMEDIATE) { 2047 2048 check = system.prepareTransactionCheckConstraint(table_def, check); 2049 Expression exp = check.expression; 2050 2051 for (int rn = 0; rn < row_indices.length; ++rn) { 2053 TableRowVariableResolver resolver = 2054 new TableRowVariableResolver(table, row_indices[rn]); 2055 TObject ob = exp.evaluate(null, resolver, context); 2056 Boolean b = ob.toBoolean(); 2057 2058 if (b != null) { 2059 if (b.equals(Boolean.FALSE)) { 2060 throw new DatabaseConstraintViolationException( 2062 DatabaseConstraintViolationException.CHECK_VIOLATION, 2063 deferredString(deferred) + " check constraint violation (" + 2064 check.name + ") - '" + exp.text() + 2065 "' evaluated to false for inserted/updated row."); 2066 } 2067 } 2068 else { 2069 transaction.Debug().write(Lvl.ERROR, 2071 TableDataConglomerate.class, 2072 deferredString(deferred) + " check constraint violation (" + 2073 check.name + ") - '" + exp.text() + 2074 "' returned a non boolean or NULL result."); 2075 } 2076 } 2078 } 2079 } 2080 2081 2082 2083 } 2084 2085 2100 static void checkAddConstraintViolations( 2101 SimpleTransaction transaction, 2102 TableDataSource table, int row_index, short deferred) { 2103 checkAddConstraintViolations(transaction, table, 2104 new int[] { row_index }, deferred); 2105 } 2106 2107 2122 static void checkRemoveConstraintViolations( 2123 SimpleTransaction transaction, TableDataSource table, 2124 int[] row_indices, short deferred) { 2125 2126 if (row_indices == null || row_indices.length == 0) { 2128 return; 2129 } 2130 2131 DataTableDef table_def = table.getDataTableDef(); 2132 TableName table_name = table_def.getTableName(); 2133 2134 Transaction.ColumnGroupReference[] foreign_constraints = 2138 Transaction.queryTableImportedForeignKeyReferences( 2139 transaction, table_name); 2140 for (int i = 0; i < foreign_constraints.length; ++i) { 2141 Transaction.ColumnGroupReference ref = foreign_constraints[i]; 2142 if (deferred == Transaction.INITIALLY_DEFERRED || 2143 ref.deferred == Transaction.INITIALLY_IMMEDIATE) { 2144 for (int rn = 0; rn < row_indices.length; ++rn) { 2146 2148 int row_count = rowCountOfReferenceTable(transaction, 2152 row_indices[rn], 2153 ref.ref_table_name, ref.ref_columns, 2154 ref.key_table_name, ref.key_columns, 2155 true); 2156 if (row_count > 0) { 2159 throw new DatabaseConstraintViolationException( 2160 DatabaseConstraintViolationException.FOREIGN_KEY_VIOLATION, 2161 deferredString(deferred)+" foreign key constraint violation " + 2162 "on delete (" + 2163 ref.name + ") Columns = " + 2164 ref.key_table_name.toString() + "( " + 2165 stringColumnList(ref.key_columns) + " ) -> " + 2166 ref.ref_table_name.toString() + "( " + 2167 stringColumnList(ref.ref_columns) + " )"); 2168 } 2169 } } 2171 } 2172 2173 } 2174 2175 2190 static void checkRemoveConstraintViolations( 2191 SimpleTransaction transaction, 2192 TableDataSource table, int row_index, short deferred) { 2193 checkRemoveConstraintViolations(transaction, table, 2194 new int[] { row_index }, deferred); 2195 } 2196 2197 2209 static void checkAllAddConstraintViolations( 2210 SimpleTransaction transaction, TableDataSource table, 2211 short deferred) { 2212 int[] rows = new int[table.getRowCount()]; 2214 RowEnumeration row_enum = table.rowEnumeration(); 2215 int p = 0; 2216 while (row_enum.hasMoreRows()) { 2217 rows[p] = row_enum.nextRowIndex(); 2218 ++p; 2219 } 2220 checkAddConstraintViolations(transaction, table, 2222 rows, Transaction.INITIALLY_DEFERRED); 2223 } 2224 2225 2226 2228 2233 Ref createNewLargeObject(byte type, long size) { 2234 try { 2235 if (isReadOnly()) { 2237 throw new RuntimeException ( 2238 "A new large object can not be allocated " + 2239 "with a read-only conglomerate"); 2240 } 2241 Ref ref = blob_store.allocateLargeObject(type, size); 2243 return ref; 2245 } 2246 catch (IOException e) { 2247 Debug().writeException(e); 2248 throw new RuntimeException ("IO Error when creating blob: " + 2249 e.getMessage()); 2250 } 2251 } 2252 2253 2260 void flushBlobStore() { 2261 } 2263 2264 2265 2267 2271 public void fix(String name, UserTerminal terminal) { 2272 this.name = name; 2273 2274 try { 2275 2276 String state_fn = (name + STATE_POST); 2277 boolean state_exists = false; 2278 try { 2279 state_exists = exists(name); 2280 } 2281 catch (IOException e) { 2282 terminal.println("IO Error when checking if state store exists: " + 2283 e.getMessage()); 2284 e.printStackTrace(); 2285 } 2286 2287 if (!state_exists) { 2288 terminal.println("Couldn't find store: " + state_fn); 2289 return; 2290 } 2291 terminal.println("+ Found state store: " + state_fn); 2292 2293 try { 2295 act_state_store = storeSystem().openStore(name + STATE_POST); 2296 state_store = new StateStore(act_state_store); 2297 Area fixed_area = act_state_store.getArea(-1); 2299 long head_p = fixed_area.getLong(); 2300 state_store.init(head_p); 2301 terminal.println("+ Initialized the state store: " + state_fn); 2302 } 2303 catch (IOException e) { 2304 terminal.println("Couldn't initialize the state file: " + state_fn + 2306 " Reason: " + e.getMessage()); 2307 return; 2308 } 2309 2310 try { 2312 initializeBlobStore(); 2313 } 2314 catch (IOException e) { 2315 terminal.println("Error intializing BlobStore: " + e.getMessage()); 2316 e.printStackTrace(); 2317 return; 2318 } 2319 setupInternal(); 2321 2322 try { 2323 checkVisibleTables(terminal); 2324 2325 terminal.println("+ RESETTING ALL SYSTEM TABLE UNIQUE ID VALUES."); 2327 resetAllSystemTableID(); 2328 2329 StringBuffer buf = new StringBuffer (); 2331 MasterTableDataSource t; 2332 StateResource[] committed_tables = state_store.getVisibleList(); 2333 StateResource[] committed_dropped = state_store.getDeleteList(); 2334 for (int i = 0; i < committed_tables.length; ++i) { 2335 terminal.println("+ COMMITTED TABLE: " + 2336 committed_tables[i].name); 2337 } 2338 for (int i = 0; i < committed_dropped.length; ++i) { 2339 terminal.println("+ COMMIT DROPPED TABLE: " + 2340 committed_dropped[i].name); 2341 } 2342 2343 return; 2344 2345 } 2346 catch (IOException e) { 2347 terminal.println("IOException: " + e.getMessage()); 2348 e.printStackTrace(); 2349 } 2350 2351 } 2352 finally { 2353 try { 2354 close(); 2355 } 2356 catch (IOException e) { 2357 terminal.println("Unable to close conglomerate after fix."); 2358 } 2359 } 2360 2361 } 2362 2363 2364 2366 2370 private static class CommitTableInfo { 2371 MasterTableDataSource master; 2373 IndexSet index_set; 2375 MasterTableJournal journal; 2378 MasterTableJournal[] changes_since_commit; 2381 int[] norm_added_rows; 2384 int[] norm_removed_rows; 2386 } 2387 2388 2392 private static boolean commitTableListContains(List list, 2393 MasterTableDataSource master) { 2394 int sz = list.size(); 2395 for (int i = 0; i < sz; ++i) { 2396 CommitTableInfo info = (CommitTableInfo) list.get(i); 2397 if (info.master.equals(master)) { 2398 return true; 2399 } 2400 } 2401 return false; 2402 } 2403 2404 2405 2406 2407 2414 2445 void processCommit(Transaction transaction, ArrayList visible_tables, 2446 ArrayList selected_from_tables, 2447 ArrayList touched_tables, TransactionJournal journal) 2448 throws TransactionException { 2449 2450 ArrayList journal_list = new ArrayList (); 2454 for (int i = 0; i < touched_tables.size(); ++i) { 2455 MasterTableJournal table_journal = 2456 ((MutableTableDataSource) touched_tables.get(i)).getJournal(); 2457 if (table_journal.entries() > 0) { journal_list.add(table_journal); 2459 } 2460 } 2461 MasterTableJournal[] changed_tables = 2462 (MasterTableJournal[]) journal_list.toArray( 2463 new MasterTableJournal[journal_list.size()]); 2464 2465 IntegerVector created_tables = journal.getTablesCreated(); 2467 IntegerVector dropped_tables = journal.getTablesDropped(); 2469 IntegerVector constraint_altered_tables = 2471 journal.getTablesConstraintAltered(); 2472 2473 if (changed_tables.length == 0 && 2475 created_tables.size() == 0 && dropped_tables.size() == 0 && 2476 constraint_altered_tables.size() == 0) { 2477 closeTransaction(transaction); 2478 return; 2479 } 2480 2481 boolean entries_committed = false; 2485 2486 ArrayList changed_tables_list = new ArrayList (); 2488 2489 synchronized (commit_lock) { 2491 2492 ArrayList database_objects_created = transaction.getAllNamesCreated(); 2495 ArrayList database_objects_dropped = transaction.getAllNamesDropped(); 2498 2499 Transaction check_transaction = null; 2502 2503 try { 2504 2505 2507 long tran_commit_id = transaction.getCommitID(); 2508 2509 if (transaction.transactionErrorOnDirtySelect()) { 2512 2513 for (int i = 0; i < selected_from_tables.size(); ++i) { 2516 MasterTableDataSource selected_table = 2517 (MasterTableDataSource) selected_from_tables.get(i); 2518 MasterTableJournal[] journals_since = 2521 selected_table.findAllJournalsSince(tran_commit_id); 2522 if (journals_since.length > 0) { 2523 throw new TransactionException( 2526 TransactionException.DIRTY_TABLE_SELECT, 2527 "Concurrent Serializable Transaction Conflict(4): " + 2528 "Select from table that has committed changes: " + 2529 selected_table.getName()); 2530 } 2531 } 2532 } 2533 2534 ArrayList all_dropped_obs = new ArrayList (); 2538 ArrayList all_created_obs = new ArrayList (); 2539 int nsj_sz = namespace_journal_list.size(); 2540 for (int i = 0; i < nsj_sz; ++i) { 2541 NameSpaceJournal ns_journal = 2542 (NameSpaceJournal) namespace_journal_list.get(i); 2543 if (ns_journal.commit_id >= tran_commit_id) { 2544 all_dropped_obs.addAll(ns_journal.dropped_names); 2545 all_created_obs.addAll(ns_journal.created_names); 2546 } 2547 } 2548 2549 int ado_sz = all_dropped_obs.size(); 2552 boolean conflict5 = false; 2553 Object conflict_name = null; 2554 String conflict_desc = ""; 2555 for (int n = 0; n < ado_sz; ++n) { 2556 if (database_objects_dropped.contains(all_dropped_obs.get(n))) { 2557 conflict5 = true; 2558 conflict_name = all_dropped_obs.get(n); 2559 conflict_desc = "Drop Clash"; 2560 } 2561 } 2562 int aco_sz = all_created_obs.size(); 2565 for (int n = 0; n < aco_sz; ++n) { 2566 if (database_objects_created.contains(all_created_obs.get(n))) { 2567 conflict5 = true; 2568 conflict_name = all_created_obs.get(n); 2569 conflict_desc = "Create Clash"; 2570 } 2571 } 2572 if (conflict5) { 2573 throw new TransactionException( 2575 TransactionException.DUPLICATE_TABLE, 2576 "Concurrent Serializable Transaction Conflict(5): " + 2577 "Namespace conflict: " + conflict_name.toString() + " " + 2578 conflict_desc); 2579 } 2580 2581 for (int i = 0; i < changed_tables.length; ++i) { 2583 MasterTableJournal change_journal = changed_tables[i]; 2584 int table_id = change_journal.getTableID(); 2586 MasterTableDataSource master = getMasterTable(table_id); 2588 2589 boolean committed_resource = 2591 state_store.containsVisibleResource(table_id); 2592 2593 if (!created_tables.contains(table_id) && 2595 !committed_resource) { 2596 throw new TransactionException( 2598 TransactionException.TABLE_DROPPED, 2599 "Concurrent Serializable Transaction Conflict(2): " + 2600 "Table altered/dropped: " + master.getName()); 2601 } 2602 2603 MasterTableJournal[] journals_since = 2608 master.findAllJournalsSince(tran_commit_id); 2609 2610 for (int n = 0; n < journals_since.length; ++n) { 2612 change_journal.testCommitClash(master.getDataTableDef(), 2614 journals_since[n]); 2615 } 2616 2617 } 2618 2619 for (int i = 0; i < dropped_tables.size(); ++i) { 2623 int table_id = dropped_tables.intAt(i); 2624 MasterTableDataSource master = getMasterTable(table_id); 2626 if (master.findAllJournalsSince(tran_commit_id).length > 0) { 2628 throw new TransactionException( 2630 TransactionException.TABLE_REMOVE_CLASH, 2631 "Concurrent Serializable Transaction Conflict(3): " + 2632 "Dropped table has modifications: " + master.getName()); 2633 } 2634 } 2635 2636 2638 2640 2645 final int created_tables_count = created_tables.size(); 2646 final int changed_tables_count = changed_tables.length; 2647 final ArrayList normalized_changed_tables = new ArrayList (8); 2648 for (int i = 0; i < changed_tables_count; ++i) { 2650 MasterTableJournal table_journal = changed_tables[i]; 2651 int table_id = table_journal.getTableID(); 2653 if (!dropped_tables.contains(table_id)) { 2656 MasterTableDataSource master_table = getMasterTable(table_id); 2657 2658 CommitTableInfo table_info = new CommitTableInfo(); 2659 table_info.master = master_table; 2660 table_info.journal = table_journal; 2661 table_info.changes_since_commit = 2662 master_table.findAllJournalsSince(tran_commit_id); 2663 2664 normalized_changed_tables.add(table_info); 2665 } 2666 } 2667 2668 for (int i = 0; i < created_tables_count; ++i) { 2670 int table_id = created_tables.intAt(i); 2671 if (!dropped_tables.contains(table_id)) { 2674 MasterTableDataSource master_table = getMasterTable(table_id); 2675 if (!commitTableListContains(normalized_changed_tables, 2676 master_table)) { 2677 2678 CommitTableInfo table_info = new CommitTableInfo(); 2680 table_info.master = master_table; 2681 2682 normalized_changed_tables.add(table_info); 2683 } 2684 } 2685 } 2686 2687 final int norm_changed_tables_count = normalized_changed_tables.size(); 2689 2690 2695 final int dropped_tables_count = dropped_tables.size(); 2696 final ArrayList normalized_dropped_tables = new ArrayList (8); 2697 for (int i = 0; i < dropped_tables_count; ++i) { 2698 int table_id = dropped_tables.intAt(i); 2700 if (!created_tables.contains(table_id)) { 2703 MasterTableDataSource master_table = getMasterTable(table_id); 2704 normalized_dropped_tables.add(master_table); 2705 } 2706 } 2707 2708 2719 2726 2732 check_transaction = createTransaction(); 2735 2736 2739 for (int i = 0; i < normalized_dropped_tables.size(); ++i) { 2742 MasterTableDataSource master_table = 2744 (MasterTableDataSource) normalized_dropped_tables.get(i); 2745 check_transaction.removeVisibleTable(master_table); 2747 } 2748 2749 2751 TableDataSource[] changed_table_source = 2753 new TableDataSource[norm_changed_tables_count]; 2754 for (int i = 0; i < norm_changed_tables_count; ++i) { 2756 2757 CommitTableInfo table_info = 2759 (CommitTableInfo) normalized_changed_tables.get(i); 2760 2761 MasterTableDataSource master = table_info.master; 2763 MasterTableJournal[] all_table_changes = 2765 table_info.changes_since_commit; 2766 2767 if (all_table_changes == null || all_table_changes.length == 0) { 2768 2771 MutableTableDataSource mtable = 2773 transaction.getTable(master.getTableName()); 2774 table_info.index_set = transaction.getIndexSetForTable(master); 2776 mtable.flushIndexChanges(); 2778 2779 check_transaction.updateVisibleTable(table_info.master, 2782 table_info.index_set); 2783 2784 } 2785 else { 2786 2789 2795 MutableTableDataSource mtable = 2798 master.createTableDataSourceAtCommit(check_transaction, 2799 table_info.journal); 2800 table_info.index_set = 2802 check_transaction.getIndexSetForTable(master); 2803 mtable.flushIndexChanges(); 2805 2806 mtable.dispose(); 2808 2809 } 2810 2811 changed_table_source[i] = 2813 check_transaction.getTable(master.getTableName()); 2814 2815 } 2816 2817 check_transaction.setReadOnly(); 2821 2822 for (int i = 0; i < constraint_altered_tables.size(); ++i) { 2825 int table_id = constraint_altered_tables.intAt(i); 2828 for (int n = 0; n < norm_changed_tables_count; ++n) { 2829 CommitTableInfo table_info = 2830 (CommitTableInfo) normalized_changed_tables.get(n); 2831 if (table_info.master.getTableID() == table_id) { 2832 checkAllAddConstraintViolations(check_transaction, 2833 changed_table_source[n], 2834 Transaction.INITIALLY_DEFERRED); 2835 } 2836 } 2837 } 2838 2839 2844 for (int i = 0; i < norm_changed_tables_count; ++i) { 2846 CommitTableInfo table_info = 2847 (CommitTableInfo) normalized_changed_tables.get(i); 2848 MasterTableJournal change_journal = table_info.journal; 2850 if (change_journal != null) { 2851 int[] normalized_removed_rows = 2853 change_journal.normalizedRemovedRows(); 2854 checkRemoveConstraintViolations(check_transaction, 2857 changed_table_source[i], normalized_removed_rows, 2858 Transaction.INITIALLY_DEFERRED); 2859 2860 int[] normalized_added_rows = 2862 change_journal.normalizedAddedRows(); 2863 checkAddConstraintViolations(check_transaction, 2866 changed_table_source[i], normalized_added_rows, 2867 Transaction.INITIALLY_DEFERRED); 2868 2869 table_info.norm_added_rows = normalized_added_rows; 2871 table_info.norm_removed_rows = normalized_removed_rows; 2872 2873 } 2874 } 2875 2876 n_loop: 2879 for (int i = 0; i < norm_changed_tables_count; ++i) { 2880 CommitTableInfo table_info = 2881 (CommitTableInfo) normalized_changed_tables.get(i); 2882 MasterTableJournal change_journal = table_info.journal; 2884 if (change_journal != null) { 2885 TableName table_name = table_info.master.getTableName(); 2887 TransactionModificationListener[] listeners; 2889 synchronized (modification_listeners) { 2891 ArrayList list = 2892 (ArrayList ) modification_listeners.get(table_name); 2893 if (list == null || list.size() == 0) { 2894 continue n_loop; 2897 } 2898 listeners = (TransactionModificationListener[]) list.toArray( 2900 new TransactionModificationListener[list.size()]); 2901 } 2902 TableCommitModificationEvent event = 2904 new TableCommitModificationEvent( 2905 check_transaction, table_name, 2906 table_info.norm_added_rows, 2907 table_info.norm_removed_rows); 2908 for (int n = 0; n < listeners.length; ++n) { 2910 listeners[n].tableCommitChange(event); 2911 } 2912 2913 } } 2916 2922 2931 entries_committed = true; 2933 2934 for (int i = 0; i < norm_changed_tables_count; ++i) { 2936 CommitTableInfo table_info = 2937 (CommitTableInfo) normalized_changed_tables.get(i); 2938 MasterTableJournal change_journal = table_info.journal; 2940 if (change_journal != null) { 2941 MasterTableDataSource master = table_info.master; 2943 master.commitTransactionChange(this.commit_id, change_journal, 2947 table_info.index_set); 2948 changed_tables_list.add(master); 2950 } 2951 } 2952 2953 if (created_tables.size() > 0 || dropped_tables.size() > 0) { 2955 commitToTables(created_tables, dropped_tables); 2958 } 2959 2960 if (database_objects_created.size() > 0 || 2962 database_objects_dropped.size() > 0) { 2963 NameSpaceJournal namespace_journal = 2964 new NameSpaceJournal(tran_commit_id, 2965 database_objects_created, 2966 database_objects_dropped); 2967 namespace_journal_list.add(namespace_journal); 2968 } 2969 2970 } 2971 finally { 2972 2973 try { 2974 2975 if (entries_committed == false) { 2979 for (int i = 0; i < changed_tables.length; ++i) { 2981 MasterTableJournal change_journal = changed_tables[i]; 2983 int table_id = change_journal.getTableID(); 2985 MasterTableDataSource master = getMasterTable(table_id); 2987 master.rollbackTransactionChange(change_journal); 2989 } 2990 if (Debug().isInterestedIn(Lvl.INFORMATION)) { 2991 Debug().write(Lvl.INFORMATION, this, 2992 "Rolled back transaction changes in a commit."); 2993 } 2994 } 2995 2996 } 2997 finally { 2998 try { 2999 if (check_transaction != null) { 3001 check_transaction.dispose(); 3002 closeTransaction(check_transaction); 3003 } 3004 closeTransaction(transaction); 3007 } 3008 catch (Throwable e) { 3009 Debug().writeException(e); 3010 } 3011 } 3012 3013 } 3014 3015 long min_commit_id = open_transactions.minimumCommitID(null); 3018 int chsz = changed_tables_list.size(); 3019 for (int i = 0; i < chsz; ++i) { 3020 MasterTableDataSource master = 3021 (MasterTableDataSource) changed_tables_list.get(i); 3022 master.mergeJournalChanges(min_commit_id); 3023 } 3024 int nsjsz = namespace_journal_list.size(); 3025 for (int i = nsjsz - 1; i >= 0; --i) { 3026 NameSpaceJournal namespace_journal = 3027 (NameSpaceJournal) namespace_journal_list.get(i); 3028 if (namespace_journal.commit_id < min_commit_id) { 3031 namespace_journal_list.remove(i); 3032 } 3033 } 3034 3035 store_system.setCheckPoint(); 3038 3039 } 3041 } 3042 3043 3049 void processRollback(Transaction transaction, 3050 ArrayList touched_tables, TransactionJournal journal) { 3051 3052 3055 ArrayList journal_list = new ArrayList (); 3059 for (int i = 0; i < touched_tables.size(); ++i) { 3060 MasterTableJournal table_journal = 3061 ((MutableTableDataSource) touched_tables.get(i)).getJournal(); 3062 if (table_journal.entries() > 0) { journal_list.add(table_journal); 3064 } 3065 } 3066 MasterTableJournal[] changed_tables = 3067 (MasterTableJournal[]) journal_list.toArray( 3068 new MasterTableJournal[journal_list.size()]); 3069 3070 IntegerVector created_tables = journal.getTablesCreated(); 3072 3073 synchronized (commit_lock) { 3074 3075 try { 3076 3077 for (int i = 0; i < changed_tables.length; ++i) { 3079 MasterTableJournal change_journal = changed_tables[i]; 3081 int table_id = change_journal.getTableID(); 3083 MasterTableDataSource master = getMasterTable(table_id); 3085 master.rollbackTransactionChange(change_journal); 3087 } 3088 3089 } 3090 finally { 3091 closeTransaction(transaction); 3093 } 3094 } 3095 } 3096 3097 3099 3106 private void commitToTables( 3107 IntegerVector created_tables, IntegerVector dropped_tables) { 3108 3109 for (int i = 0; i < created_tables.size(); ++i) { 3111 MasterTableDataSource t = getMasterTable(created_tables.intAt(i)); 3114 StateResource resource = 3115 new StateResource(t.getTableID(), createEncodedTableFile(t)); 3116 state_store.addVisibleResource(resource); 3117 state_store.removeDeleteResource(resource.name); 3118 } 3119 3120 for (int i = 0; i < dropped_tables.size(); ++i) { 3122 MasterTableDataSource t = getMasterTable(dropped_tables.intAt(i)); 3125 StateResource resource = 3126 new StateResource(t.getTableID(), createEncodedTableFile(t)); 3127 state_store.addDeleteResource(resource); 3128 state_store.removeVisibleResource(resource.name); 3129 } 3130 3131 try { 3132 state_store.commit(); 3133 } 3134 catch (IOException e) { 3135 Debug().writeException(e); 3136 throw new Error ("IO Error: " + e.getMessage()); 3137 } 3138 } 3139 3140 3144 MasterTableDataSource getMasterTable(int table_id) { 3145 synchronized (commit_lock) { 3146 for (int i = 0; i < table_list.size(); ++i) { 3148 MasterTableDataSource t = (MasterTableDataSource) table_list.get(i); 3149 if (t.getTableID() == table_id) { 3150 return t; 3151 } 3152 } 3153 throw new Error ("Unable to find an open table with id: " + table_id); 3154 } 3155 } 3156 3157 3171 MasterTableDataSource createMasterTable(DataTableDef table_def, 3172 int data_sector_size, int index_sector_size) { 3173 synchronized (commit_lock) { 3174 try { 3175 3176 3180 int table_id = nextUniqueTableID(); 3182 3183 V2MasterTableDataSource master_table = 3185 new V2MasterTableDataSource(getSystem(), 3186 storeSystem(), open_transactions, blob_store); 3187 master_table.create(table_id, table_def); 3188 3189 table_list.add(master_table); 3191 3192 markAsCommittedDropped(table_id); 3195 3196 state_store.commit(); 3198 3199 return master_table; 3201 3202 } 3203 catch (IOException e) { 3204 Debug().writeException(e); 3205 throw new Error ("Unable to create master table '" + 3206 table_def.getName() + "' - " + e.getMessage()); 3207 } 3208 } 3209 3210 } 3211 3212 3225 MasterTableDataSource copyMasterTable( 3226 MasterTableDataSource src_master_table, IndexSet index_set) { 3227 synchronized (commit_lock) { 3228 try { 3229 3230 3234 int table_id = nextUniqueTableID(); 3236 3237 V2MasterTableDataSource master_table = 3239 new V2MasterTableDataSource(getSystem(), 3240 storeSystem(), open_transactions, blob_store); 3241 3242 master_table.copy(table_id, src_master_table, index_set); 3243 3244 table_list.add(master_table); 3246 3247 markAsCommittedDropped(table_id); 3250 3251 state_store.commit(); 3253 3254 return master_table; 3256 3257 } 3258 catch (IOException e) { 3259 Debug().writeException(e); 3260 throw new RuntimeException ("Unable to copy master table '" + 3261 src_master_table.getDataTableDef().getName() + 3262 "' - " + e.getMessage()); 3263 } 3264 } 3265 3266 } 3267 3268 3270 3276 private static class NameSpaceJournal { 3277 3278 3281 long commit_id; 3282 3283 3286 ArrayList created_names; 3287 3288 3291 ArrayList dropped_names; 3292 3293 3296 NameSpaceJournal(long commit_id, 3297 ArrayList created_names, ArrayList dropped_names) { 3298 this.commit_id = commit_id; 3299 this.created_names = created_names; 3300 this.dropped_names = dropped_names; 3301 } 3302 3303 } 3304 3305 3306 3347 public void finalize() { 3348 } 3350 3351 3352 3353} 3354 | Popular Tags |