1 24 25 package org.objectweb.cjdbc.controller.recoverylog; 26 27 import java.sql.Connection ; 28 import java.sql.DatabaseMetaData ; 29 import java.sql.PreparedStatement ; 30 import java.sql.ResultSet ; 31 import java.sql.SQLException ; 32 import java.sql.Statement ; 33 import java.util.ArrayList ; 34 35 import org.objectweb.cjdbc.common.exceptions.VirtualDatabaseException; 36 import org.objectweb.cjdbc.common.i18n.Translate; 37 import org.objectweb.cjdbc.common.log.Trace; 38 import org.objectweb.cjdbc.common.shared.BackendState; 39 import org.objectweb.cjdbc.common.shared.DumpInfo; 40 import org.objectweb.cjdbc.common.sql.AbstractRequest; 41 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest; 42 import org.objectweb.cjdbc.common.sql.AlterRequest; 43 import org.objectweb.cjdbc.common.sql.CreateRequest; 44 import org.objectweb.cjdbc.common.sql.DeleteRequest; 45 import org.objectweb.cjdbc.common.sql.DropRequest; 46 import org.objectweb.cjdbc.common.sql.InsertRequest; 47 import org.objectweb.cjdbc.common.sql.StoredProcedure; 48 import org.objectweb.cjdbc.common.sql.UpdateRequest; 49 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 50 import org.objectweb.cjdbc.common.xml.XmlComponent; 51 import org.objectweb.cjdbc.controller.connection.DriverManager; 52 import org.objectweb.cjdbc.controller.loadbalancer.tasks.BeginTask; 53 import org.objectweb.cjdbc.controller.loadbalancer.tasks.CommitTask; 54 import org.objectweb.cjdbc.controller.loadbalancer.tasks.ReadStoredProcedureTask; 55 import org.objectweb.cjdbc.controller.loadbalancer.tasks.ReleaseSavepointTask; 56 import org.objectweb.cjdbc.controller.loadbalancer.tasks.RollbackTask; 57 import org.objectweb.cjdbc.controller.loadbalancer.tasks.RollbackToSavepointTask; 58 import org.objectweb.cjdbc.controller.loadbalancer.tasks.SavepointTask; 59 import org.objectweb.cjdbc.controller.loadbalancer.tasks.WriteRequestTask; 60 import org.objectweb.cjdbc.controller.loadbalancer.tasks.WriteStoredProcedureTask; 61 import org.objectweb.cjdbc.controller.recoverylog.events.LogEntry; 62 import org.objectweb.cjdbc.controller.recoverylog.events.LogRequestEvent; 63 import org.objectweb.cjdbc.controller.recoverylog.events.LogRollbackEvent; 64 import org.objectweb.cjdbc.controller.recoverylog.events.ResetLogEvent; 65 import org.objectweb.cjdbc.controller.recoverylog.events.StoreDumpCheckpointEvent; 66 import org.objectweb.cjdbc.controller.recoverylog.events.UnlogRequestEvent; 67 import org.objectweb.cjdbc.controller.requestmanager.TransactionMarkerMetaData; 68 69 79 public class RecoveryLog implements XmlComponent 80 { 81 static Trace logger = Trace 82 .getLogger("org.objectweb.cjdbc.controller.recoverylog"); 83 84 85 private long recoveringNb = 0; 86 87 88 protected int recoveryBatchSize; 89 90 91 private String driverClassName; 92 93 94 private String driverName; 95 96 97 private String url; 98 99 100 private String login; 101 102 103 private String password; 104 105 106 private Connection internalConnectionManagedByGetDatabaseConnection = null; 107 108 114 private String logTableCreateTable; 115 private String logTableName; 116 private String logTableCreateStatement; 117 private String logTableIdType; 118 private String logTableVloginType; 119 private String logTableSqlColumnName; 120 private String logTableSqlType; 121 private String logTableTransactionIdType; 122 private String logTableExtraStatement; 123 124 130 private String checkpointTableCreateTable; 131 private String checkpointTableName; 132 private String checkpointTableCreateStatement; 133 private String checkpointTableNameType; 134 private String checkpointTableRequestIdType; 135 private String checkpointTableExtraStatement; 136 137 143 private String backendTableCreateStatement; 144 private String backendTableName; 145 private String backendTableCreateTable; 146 private String backendTableDatabaseName; 147 private String backendTableExtraStatement; 148 private String backendTableCheckpointName; 149 private String backendTableBackendState; 150 private String backendTableBackendName; 151 152 158 private String dumpTableCreateStatement; 159 private String dumpTableCreateTable; 160 private String dumpTableName; 161 private String dumpTableDumpNameColumnType; 162 private String dumpTableDumpDateColumnType; 163 private String dumpTableDumpPathColumnType; 164 private String dumpTableDumpFormatColumnType; 165 private String dumpTableCheckpointNameColumnType; 166 private String dumpTableBackendNameColumnType; 167 private String dumpTableTablesColumnName; 168 private String dumpTableTablesColumnType; 169 private String dumpTableExtraStatementDefinition; 170 171 172 private long logTableId = 0; 173 174 175 private int timeout; 176 177 private LoggerThread loggerThread; 178 179 191 public RecoveryLog(String driverName, String driverClassName, String url, 192 String login, String password, int requestTimeout, int recoveryBatchSize) 193 { 194 this.driverName = driverName; 195 this.driverClassName = driverClassName; 196 this.url = url; 197 this.login = login; 198 this.password = password; 199 this.timeout = requestTimeout; 200 if (recoveryBatchSize < 1) 201 { 202 logger 203 .warn("RecoveryBatchSize was set to a value lesser than 1, resetting value to 1."); 204 recoveryBatchSize = 1; 205 } 206 this.recoveryBatchSize = recoveryBatchSize; 207 208 try 210 { 211 getDatabaseConnection(); 212 } 213 catch (SQLException e) 214 { 215 throw new RuntimeException ("Unable to connect to the database: " + e); 216 } 217 218 } 221 222 226 233 protected Connection getDatabaseConnection() throws SQLException 234 { 235 try 236 { 237 if (internalConnectionManagedByGetDatabaseConnection == null) 238 { 239 if (logger.isDebugEnabled()) 240 logger.debug(Translate.get("recovery.jdbc.connect", new String []{url, 241 login})); 242 internalConnectionManagedByGetDatabaseConnection = DriverManager 243 .getConnection(url, login, password, driverName, driverClassName); 244 } 245 return internalConnectionManagedByGetDatabaseConnection; 246 } 247 catch (RuntimeException e) 248 { 249 String msg = Translate.get("recovery.jdbc.connect.failed", e); 250 if (logger.isDebugEnabled()) 251 logger.debug(msg, e); 252 throw new SQLException (msg); 253 } 254 catch (SQLException e) 255 { 256 invalidateInternalConnection(); 257 String msg = Translate.get("recovery.jdbc.connect.failed", e); 258 if (logger.isDebugEnabled()) 259 logger.debug(msg, e); 260 throw new SQLException (msg); 261 } 262 } 263 264 267 private synchronized long incrementLogTableId() 268 { 269 logTableId++; 270 return logTableId; 271 } 272 273 277 private void intializeDatabase() throws SQLException 278 { 279 boolean createLogTable = true; 280 boolean createCheckpointTable = true; 281 boolean createBackendTable = true; 282 boolean createDumpTable = true; 283 Connection connection; 284 try 286 { 287 connection = getDatabaseConnection(); 288 connection.setAutoCommit(false); 289 DatabaseMetaData metaData = connection.getMetaData(); 291 292 String [] types = {"TABLE", "VIEW"}; 299 ResultSet rs = metaData.getTables(null, null, "%", types); 300 301 String tableName; 303 while (rs.next()) 304 { 305 tableName = rs.getString(3); 307 if (logger.isDebugEnabled()) 308 logger.debug(Translate.get("recovery.jdbc.table.found", tableName)); 309 if (tableName.equalsIgnoreCase(logTableName)) 310 { 311 if (tableName.compareTo(logTableName) != 0) 312 logger.warn(Translate.get("recovery.jdbc.logtable.case.mismatch", 313 new String []{logTableName, tableName})); 314 createLogTable = false; 315 PreparedStatement p = null; 317 try 318 { 319 ResultSet result = null; 320 p = connection.prepareStatement("SELECT MAX(id) AS max_id FROM " 321 + logTableName); 322 result = p.executeQuery(); 323 if (result.next()) 324 logTableId = result.getLong("max_id"); 325 else 326 logTableId = 0; 327 p.close(); 328 } 329 catch (SQLException e) 330 { 331 try 332 { 333 if (p != null) 334 p.close(); 335 } 336 catch (Exception ignore) 337 { 338 } 339 throw new RuntimeException (Translate.get( 340 "recovery.jdbc.logtable.getvalue.failed", e)); 341 } 342 343 } 344 if (tableName.equalsIgnoreCase(checkpointTableName)) 345 { 346 if (tableName.compareTo(checkpointTableName) != 0) 347 logger.warn(Translate.get( 348 "recovery.jdbc.checkpointtable.case.mismatch", new String []{ 349 checkpointTableName, tableName})); 350 createCheckpointTable = false; 351 } 352 else if (tableName.equalsIgnoreCase(backendTableName)) 353 { 354 if (tableName.compareTo(backendTableName) != 0) 355 logger.warn(Translate.get( 356 "recovery.jdbc.backendtable.case.mismatch", new String []{ 357 backendTableName, tableName})); 358 createBackendTable = false; 359 } 360 else if (tableName.equalsIgnoreCase(dumpTableName)) 361 { 362 if (tableName.compareTo(dumpTableName) != 0) 363 logger.warn(Translate.get("recovery.jdbc.dumptable.case.mismatch", 364 new String []{backendTableName, tableName})); 365 createDumpTable = false; 366 } 367 } 368 try 369 { 370 connection.commit(); 371 connection.setAutoCommit(true); 372 } 373 catch (Exception ignore) 374 { 375 } 377 } 378 catch (SQLException e) 379 { 380 logger.error(Translate.get("recovery.jdbc.table.no.description"), e); 381 throw e; 382 } 383 384 Statement stmt = null; 386 if (createLogTable) 387 { 388 if (logger.isInfoEnabled()) 389 logger.info(Translate 390 .get("recovery.jdbc.logtable.create", logTableName)); 391 try 392 { 393 stmt = connection.createStatement(); 394 stmt.executeUpdate(logTableCreateStatement); 395 stmt.close(); 396 } 397 catch (SQLException e) 398 { 399 throw new SQLException (Translate.get( 400 "recovery.jdbc.logtable.create.failed", new String []{logTableName, 401 e.getMessage()})); 402 } 403 } 404 if (createCheckpointTable) 405 { 406 if (logger.isInfoEnabled()) 407 logger.info(Translate.get("recovery.jdbc.checkpointtable.create", 408 checkpointTableName)); 409 try 410 { 411 stmt = connection.createStatement(); 412 stmt.executeUpdate(checkpointTableCreateStatement); 413 stmt.close(); 414 } 415 catch (SQLException e) 416 { 417 throw new SQLException (Translate.get( 418 "recovery.jdbc.checkpointtable.create.failed", new String []{ 419 logTableName, e.getMessage()})); 420 } 421 422 String checkpointName = "Initial_empty_recovery_log"; 424 PreparedStatement pstmt = null; 425 try 426 { 427 if (logger.isDebugEnabled()) 428 logger.debug("Storing checkpoint " + checkpointName 429 + " at request id " + logTableId); 430 pstmt = connection.prepareStatement("INSERT INTO " 431 + checkpointTableName + " VALUES(?,?)"); 432 pstmt.setString(1, checkpointName); 433 pstmt.setLong(2, logTableId); 434 pstmt.executeUpdate(); 435 pstmt.close(); 436 } 437 catch (SQLException e) 438 { 439 try 440 { 441 if (pstmt != null) 442 pstmt.close(); 443 } 444 catch (Exception ignore) 445 { 446 } 447 throw new SQLException (Translate.get( 448 "recovery.jdbc.checkpoint.store.failed", new String []{ 449 checkpointName, e.getMessage()})); 450 } 451 } 452 if (createBackendTable) 453 { 454 if (logger.isInfoEnabled()) 455 logger.info(Translate.get("recovery.jdbc.backendtable.create", 456 backendTableName)); 457 try 458 { 459 stmt = connection.createStatement(); 460 stmt.executeUpdate(backendTableCreateStatement); 461 stmt.close(); 462 } 463 catch (SQLException e) 464 { 465 throw new SQLException (Translate.get( 466 "recovery.jdbc.backendtable.create.failed", new String []{ 467 logTableName, e.getMessage()})); 468 } 469 } 470 if (createDumpTable) 471 { 472 if (logger.isInfoEnabled()) 473 logger.info(Translate.get("recovery.jdbc.dumptable.create", 474 dumpTableName)); 475 try 476 { 477 stmt = connection.createStatement(); 478 stmt.executeUpdate(dumpTableCreateStatement); 479 stmt.close(); 480 } 481 catch (SQLException e) 482 { 483 throw new SQLException (Translate.get( 484 "recovery.jdbc.dumptable.create.failed", new String []{ 485 dumpTableName, e.getMessage()})); 486 } 487 } 488 } 489 490 496 protected void invalidateInternalConnection() 497 { 498 try 499 { 500 internalConnectionManagedByGetDatabaseConnection.close(); 501 } 502 catch (Exception ignore) 503 { 504 } 505 internalConnectionManagedByGetDatabaseConnection = null; 506 } 507 508 514 523 public long logAbort(TransactionMarkerMetaData tm) 524 { 525 return logRollback(tm); 527 } 528 529 535 public long logBegin(TransactionMarkerMetaData tm) 536 { 537 long id = incrementLogTableId(); 539 loggerThread.log(new LogRequestEvent(new LogEntry(id, tm.getLogin(), 540 "begin", tm.getTransactionId(), false))); 541 return id; 542 } 543 544 550 public long logCommit(TransactionMarkerMetaData tm) 551 { 552 long id = incrementLogTableId(); 553 loggerThread.log(new LogRequestEvent(new LogEntry(id, tm.getLogin(), 554 "commit", tm.getTransactionId(), false))); 555 return id; 556 } 557 558 563 public void logLogEntry(LogEntry logEntry) 564 { 565 loggerThread.log(new LogRequestEvent(logEntry)); 566 } 567 568 575 public long logReleaseSavepoint(TransactionMarkerMetaData tm, String name) 576 { 577 long id = incrementLogTableId(); 578 loggerThread.log(new LogRequestEvent(new LogEntry(id, tm.getLogin(), 579 "release " + name, tm.getTransactionId(), false))); 580 return id; 581 } 582 583 589 public long logRequest(AbstractWriteRequest request) 590 { 591 long id = incrementLogTableId(); 592 loggerThread.log(new LogRequestEvent(new LogEntry(id, request.getLogin(), 593 request.getSQL(), request.getTransactionId(), request 594 .getEscapeProcessing()))); 595 return id; 596 } 597 598 605 public long logRequest(StoredProcedure proc, boolean isRead) 606 { 607 long id = incrementLogTableId(); 608 if (isRead) 609 loggerThread.log(new LogRequestEvent(new LogEntry(incrementLogTableId(), 610 proc.getLogin(), proc.getSQL(), proc.getTransactionId(), proc 611 .getEscapeProcessing()))); 612 else 613 { StringBuffer writeCall = new StringBuffer (proc.getSQL()); 615 writeCall.setCharAt(0, '}'); 616 loggerThread.log(new LogRequestEvent(new LogEntry(incrementLogTableId(), 617 proc.getLogin(), writeCall.toString(), proc.getTransactionId(), proc 618 .getEscapeProcessing()))); 619 } 620 return id; 621 } 622 623 629 public long logRollback(TransactionMarkerMetaData tm) 630 { 631 long id = incrementLogTableId(); 632 loggerThread.log(new LogRollbackEvent(new LogEntry(id, tm.getLogin(), 634 "rollback", tm.getTransactionId(), false))); 635 return id; 636 } 637 638 645 public long logRollback(TransactionMarkerMetaData tm, String savepointName) 646 { 647 long id = incrementLogTableId(); 648 loggerThread.log(new LogRequestEvent(new LogEntry(id, tm.getLogin(), 649 "rollback " + savepointName, tm.getTransactionId(), false))); 650 return id; 651 } 652 653 660 public long logSetSavepoint(TransactionMarkerMetaData tm, String name) 661 { 662 long id = incrementLogTableId(); 663 loggerThread.log(new LogRequestEvent(new LogEntry(id, tm.getLogin(), 664 "savepoint " + name, tm.getTransactionId(), false))); 665 return id; 666 } 667 668 678 public void resetLogTableIdAndDeleteRecoveryLog(String checkpointName, 679 long newCheckpointId) throws SQLException 680 { 681 long oldId = getCheckpointRequestId(checkpointName); 682 synchronized (this) 683 { 684 loggerThread 687 .log(new ResetLogEvent(oldId, newCheckpointId, checkpointName)); 688 logTableId = newCheckpointId + logTableId - oldId; 689 } 690 } 691 692 700 public void unlogCommit(TransactionMarkerMetaData tm) 701 { 702 loggerThread.log(new UnlogRequestEvent(new LogEntry(tm.getTimeout(), tm 704 .getLogin(), "commit", tm.getTransactionId(), false))); 705 } 706 707 717 public void unlogRequest(AbstractRequest request) 718 { 719 loggerThread.log(new UnlogRequestEvent(new LogEntry(request.getId(), 720 request.getLogin(), request.getSQL(), request.getTransactionId(), 721 request.getEscapeProcessing()))); 722 } 723 724 733 public void unlogRequest(StoredProcedure proc) 734 { 735 StringBuffer writeCall = new StringBuffer (proc.getSQL()); 738 writeCall.setCharAt(0, '}'); 739 loggerThread.log(new UnlogRequestEvent(new LogEntry(proc.getId(), proc 740 .getLogin(), writeCall.toString(), proc.getTransactionId(), proc 741 .getEscapeProcessing()))); 742 } 743 744 752 public void unlogRollback(TransactionMarkerMetaData tm) 753 { 754 loggerThread.log(new UnlogRequestEvent(new LogEntry(tm.getTimeout(), tm 756 .getLogin(), "rollback", tm.getTransactionId(), false))); 757 } 758 759 762 public void shutdown() 763 { 764 if (loggerThread != null) 765 loggerThread.shutdown(); 766 } 767 768 772 775 public synchronized void beginRecovery() 776 { 777 recoveringNb++; 778 } 779 780 786 public void cleanRecoveryLog() throws SQLException 787 { 788 PreparedStatement stmt = null; 789 790 ResultSet rs = null; 792 try 793 { 794 stmt = getDatabaseConnection().prepareStatement( 796 "SELECT transaction_id FROM " + logTableName + " WHERE " 797 + logTableSqlColumnName + " LIKE ?"); 798 stmt.setString(1, "rollback"); 799 rs = stmt.executeQuery(); 800 } 801 catch (SQLException e) 802 { 803 invalidateInternalConnection(); 804 try 805 { 806 if (stmt != null) 807 stmt.close(); 808 } 809 catch (Exception ignore) 810 { 811 } 812 throw new SQLException ("Unable get rollback statements : " + e); 813 } 814 PreparedStatement pstmt = null; 815 long transactionId = -1; 816 try 817 { 818 while (rs.next()) 820 { 821 transactionId = rs.getLong("transaction_id"); 822 pstmt = getDatabaseConnection().prepareStatement( 823 "DELETE FROM " + logTableName + " WHERE transaction_id=?"); 824 pstmt.setLong(1, transactionId); 825 pstmt.executeUpdate(); 826 pstmt.close(); 827 } 828 rs.close(); 829 stmt.close(); 830 } 831 catch (SQLException e) 832 { 833 invalidateInternalConnection(); 834 throw new SQLException (Translate.get( 835 "recovery.jdbc.transaction.remove.failed", new String []{ 836 String.valueOf(transactionId), e.getMessage()})); 837 } 838 finally 839 { 840 try 841 { 842 if (stmt != null) 843 stmt.close(); 844 } 845 catch (Exception ignore) 846 { 847 } 848 try 849 { 850 if (pstmt != null) 851 pstmt.close(); 852 } 853 catch (Exception ignore) 854 { 855 } 856 857 } 858 } 859 860 866 public synchronized void endRecovery() 867 { 868 recoveringNb--; 869 if (recoveringNb == 0) 870 { 871 try 872 { 873 cleanRecoveryLog(); 874 } 875 catch (SQLException e) 876 { 877 logger.error(Translate.get("recovery.cleaning.failed"), e); 878 } 879 } 880 } 881 882 890 public BackendRecoveryInfo getBackendRecoveryInfo(String databaseName, 891 String backendName) 892 { 893 PreparedStatement stmt = null; 894 String checkpoint = null; 895 int backendState = BackendState.UNKNOWN; 896 try 897 { 898 stmt = getDatabaseConnection().prepareStatement( 900 "SELECT * FROM " + backendTableName 901 + " WHERE backend_name LIKE ? AND database_name LIKE ?"); 902 stmt.setString(1, backendName); 903 stmt.setString(2, databaseName); 904 ResultSet rs = stmt.executeQuery(); 905 906 if (rs.next()) 907 { 908 checkpoint = rs.getString("checkpoint_name"); 909 backendState = rs.getInt("backend_state"); 910 } 911 rs.close(); 912 } 913 catch (SQLException e) 914 { 915 invalidateInternalConnection(); 916 logger.info( 917 "An error occured while retrieving backend recovery information", e); 918 } 919 finally 920 { 921 try 922 { 923 if (stmt != null) 924 stmt.close(); 925 } 926 catch (Exception ignore) 927 { 928 } 929 } 930 return new BackendRecoveryInfo(backendName, checkpoint, backendState, 931 databaseName); 932 } 933 934 940 public long getLastTransactionId() throws SQLException 941 { 942 Statement stmt = null; 943 ResultSet rs = null; 944 try 945 { 946 stmt = getDatabaseConnection().createStatement(); 947 rs = stmt.executeQuery("select max(transaction_id) from " + logTableName); 948 if (rs.next()) 949 return rs.getLong(1); 950 else 951 return 0; 953 } 954 catch (SQLException e) 955 { 956 invalidateInternalConnection(); 957 throw e; 958 } 959 finally 960 { 961 try 962 { 963 if (rs != null) 964 rs.close(); 965 } 966 catch (Exception ignore) 967 { 968 } 969 try 970 { 971 if (stmt != null) 972 stmt.close(); 973 } 974 catch (Exception ignore) 975 { 976 } 977 } 978 } 979 980 985 public long getRecoveringNb() 986 { 987 return recoveringNb; 988 } 989 990 995 public int getRecoveryBatchSize() 996 { 997 return recoveryBatchSize; 998 } 999 1000 1006 public synchronized boolean isRecovering() 1007 { 1008 return recoveringNb > 0; 1009 } 1010 1011 1020 public LogEntry getNextLogEntry(long previousLogEntryId) throws SQLException 1021 { 1022 ResultSet rs = null; 1023 boolean emptyResult; 1024 PreparedStatement stmt = null; 1025 try 1026 { 1027 stmt = getDatabaseConnection().prepareStatement( 1028 "SELECT * FROM " + logTableName + " WHERE id=?"); 1029 do 1031 { 1032 previousLogEntryId++; 1033 stmt.setLong(1, previousLogEntryId); 1034 if (rs != null) 1036 rs.close(); 1037 rs = stmt.executeQuery(); 1038 emptyResult = !rs.next(); 1039 } 1040 while (emptyResult && (previousLogEntryId <= logTableId)); 1041 1042 if (emptyResult) 1044 return null; 1045 1046 long id = rs.getLong("id"); 1049 String user = rs.getString("vlogin"); 1050 String sql = rs.getString(logTableSqlColumnName); 1051 long transactionId = rs.getLong("transaction_id"); 1052 return new LogEntry(id, user, sql, transactionId, true); 1055 } 1056 catch (SQLException e) 1057 { 1058 invalidateInternalConnection(); 1059 throw new SQLException (Translate.get("recovery.jdbc.recover.failed", e)); 1060 } 1061 finally 1062 { 1063 try 1064 { 1065 if (rs != null) 1066 rs.close(); 1067 } 1068 catch (Exception ignore) 1069 { 1070 } 1071 try 1072 { 1073 if (stmt != null) 1074 stmt.close(); 1075 } 1076 catch (Exception ignore) 1077 { 1078 } 1079 } 1080 } 1081 1082 1095 public RecoveryTask recoverNextRequest(long previousRequestId) 1096 throws SQLException 1097 { 1098 RecoveryTask task = null; 1099 1100 LogEntry logEntry = getNextLogEntry(previousRequestId); 1102 if (logEntry == null) 1103 return null; 1104 1105 long transactionId = logEntry.getTid(); 1107 long id = logEntry.getId(); 1108 String user = logEntry.getLogin(); 1109 String sql = logEntry.getQuery().trim(); 1110 1111 boolean escapeProcessing = true; 1112 String lower = sql.substring(0, 2).toLowerCase(); 1116 if (lower.equals("in")) 1117 { AbstractWriteRequest wr = new InsertRequest(sql, escapeProcessing, 1120 timeout, "\n", false ); 1121 wr.setLogin(user); 1122 if (logger.isDebugEnabled()) 1123 logger.debug("insert request: " + sql); 1124 setDriverProcessedAndSkeleton(wr); 1125 if (transactionId != 0) 1126 { 1127 wr.setIsAutoCommit(false); 1128 wr.setTransactionId(transactionId); 1129 } 1130 else 1131 wr.setIsAutoCommit(true); 1132 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1133 } 1134 else if (lower.equals("up")) 1135 { AbstractWriteRequest wr = new UpdateRequest(sql, escapeProcessing, 1137 timeout, "\n"); 1138 wr.setLogin(user); 1139 setDriverProcessedAndSkeleton(wr); 1140 if (logger.isDebugEnabled()) 1141 logger.debug("update request: " + sql); 1142 if (transactionId != 0) 1143 { 1144 wr.setIsAutoCommit(false); 1145 wr.setTransactionId(transactionId); 1146 } 1147 else 1148 wr.setIsAutoCommit(true); 1149 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1150 } 1151 else if (lower.equals("de")) 1152 { AbstractWriteRequest wr = new DeleteRequest(sql, escapeProcessing, 1154 timeout, "\n"); 1155 wr.setLogin(user); 1156 setDriverProcessedAndSkeleton(wr); 1157 if (logger.isDebugEnabled()) 1158 logger.debug("delete request: " + sql); 1159 if (transactionId != 0) 1160 { 1161 wr.setIsAutoCommit(false); 1162 wr.setTransactionId(transactionId); 1163 } 1164 else 1165 wr.setIsAutoCommit(true); 1166 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1167 } 1168 else if (lower.equals("cr")) 1169 { AbstractWriteRequest wr = new CreateRequest(sql, escapeProcessing, 1171 timeout, "\n"); 1172 wr.setLogin(user); 1173 setDriverProcessedAndSkeleton(wr); 1174 if (logger.isDebugEnabled()) 1175 logger.debug("create request: " + sql); 1176 if (transactionId != 0) 1177 { 1178 wr.setIsAutoCommit(false); 1179 wr.setTransactionId(transactionId); 1180 } 1181 else 1182 wr.setIsAutoCommit(true); 1183 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1184 } 1185 else if (lower.equals("al")) 1186 { AbstractWriteRequest wr = new AlterRequest(sql, escapeProcessing, 1188 timeout, "\n"); 1189 wr.setLogin(user); 1190 setDriverProcessedAndSkeleton(wr); 1191 if (logger.isDebugEnabled()) 1192 logger.debug("alter request: " + sql); 1193 if (transactionId != 0) 1194 { 1195 wr.setIsAutoCommit(false); 1196 wr.setTransactionId(transactionId); 1197 } 1198 else 1199 wr.setIsAutoCommit(true); 1200 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1201 } 1202 else if (lower.equals("dr")) 1203 { AbstractWriteRequest wr = new DropRequest(sql, escapeProcessing, timeout, 1205 "\n"); 1206 wr.setLogin(user); 1207 setDriverProcessedAndSkeleton(wr); 1208 if (logger.isDebugEnabled()) 1209 logger.debug("drop request: " + sql); 1210 if (transactionId != 0) 1211 { 1212 wr.setIsAutoCommit(false); 1213 wr.setTransactionId(transactionId); 1214 } 1215 else 1216 wr.setIsAutoCommit(true); 1217 task = new RecoveryTask(transactionId, id, new WriteRequestTask(1, 1, wr)); 1218 } 1219 else if (lower.equals("be")) 1220 { task = new RecoveryTask(transactionId, id, new BeginTask(1, 1, 1222 (long) timeout * 1000, user, transactionId)); 1223 if (logger.isDebugEnabled()) 1224 logger.debug("begin transaction: " + transactionId); 1225 } 1226 else if (lower.equals("co")) 1227 { task = new RecoveryTask(transactionId, id, new CommitTask(1, 1, 1229 (long) timeout * 1000, user, transactionId)); 1230 if (logger.isDebugEnabled()) 1231 logger.debug("commit transaction: " + transactionId); 1232 } 1233 else if (lower.equals("ro")) 1234 { int index = sql.indexOf(' '); 1236 if (index == -1) 1237 { 1238 task = new RecoveryTask(transactionId, id, new RollbackTask(1, 1, 1239 (long) timeout * 1000, user, transactionId)); 1240 if (logger.isDebugEnabled()) 1241 logger.debug("rollback transaction: " + transactionId); 1242 } 1243 else 1244 { 1245 String savepointName = sql.substring(index); 1246 task = new RecoveryTask(transactionId, id, new RollbackToSavepointTask( 1247 1, 1, (long) timeout * 1000, user, transactionId, savepointName)); 1248 if (logger.isDebugEnabled()) 1249 logger.debug("rollback transaction to savepoint: " + transactionId); 1250 } 1251 } 1252 else if (lower.equals("sa")) 1253 { String savepointName = sql.substring(sql.indexOf(' ')); 1255 task = new RecoveryTask(transactionId, id, new SavepointTask(1, 1, 1256 (long) timeout * 1000, user, transactionId, savepointName)); 1257 if (logger.isDebugEnabled()) 1258 logger.debug("transaction set savepoint: " + transactionId); 1259 } 1260 else if (lower.equals("re")) 1261 { String savepointName = sql.substring(sql.indexOf(' ')); 1263 task = new RecoveryTask(transactionId, id, new ReleaseSavepointTask(1, 1, 1264 (long) timeout * 1000, user, transactionId, savepointName)); 1265 if (logger.isDebugEnabled()) 1266 logger.debug("transaction release savepoint: " + transactionId); 1267 } 1268 else if (lower.equals("{c")) 1269 { StoredProcedure proc = new StoredProcedure(sql, escapeProcessing, 1271 timeout, "\n", true ); 1272 proc.setLogin(user); 1273 setDriverProcessedAndSkeleton(proc); 1274 if (logger.isDebugEnabled()) 1275 logger.debug("read stored procedure call: " + sql); 1276 if (transactionId != 0) 1277 { 1278 proc.setIsAutoCommit(false); 1279 proc.setTransactionId(transactionId); 1280 } 1281 else 1282 proc.setIsAutoCommit(true); 1283 task = new RecoveryTask(transactionId, id, new ReadStoredProcedureTask(1, 1284 1, proc, null)); 1285 } 1286 else if (lower.equals("}c")) 1287 { StringBuffer writeCall = new StringBuffer (sql); 1290 writeCall.setCharAt(0, '{'); 1291 StoredProcedure proc = new StoredProcedure(writeCall.toString(), 1292 escapeProcessing, timeout, "\n", false ); 1293 proc.setLogin(user); 1294 setDriverProcessedAndSkeleton(proc); 1295 if (logger.isDebugEnabled()) 1296 logger.debug("write stored procedure call: " + sql); 1297 if (transactionId != 0) 1298 { 1299 proc.setIsAutoCommit(false); 1300 proc.setTransactionId(transactionId); 1301 } 1302 else 1303 proc.setIsAutoCommit(true); 1304 task = new RecoveryTask(transactionId, id, new WriteStoredProcedureTask( 1305 1, 1, proc)); 1306 } 1307 else 1308 throw new SQLException (Translate.get("recovery.jdbc.sql.unkwown", sql)); 1309 return task; 1310 } 1311 1312 1318 1327 public void deleteLogEntriesBeforeCheckpoint(String checkpointName) 1328 throws SQLException 1329 { 1330 long id = getCheckpointRequestId(checkpointName); 1331 PreparedStatement stmt = null; 1332 try 1333 { 1334 stmt = getDatabaseConnection().prepareStatement( 1335 "DELETE FROM " + getLogTableName() + " WHERE id<=?"); 1336 stmt.setLong(1, id); 1337 stmt.executeUpdate(); 1338 } 1339 catch (SQLException e) 1340 { 1341 throw new SQLException (Translate.get( 1343 "recovery.jdbc.transaction.remove.failed", new String []{ 1344 String.valueOf(id), e.getMessage()})); 1345 } 1346 finally 1347 { 1348 try 1349 { 1350 if (stmt != null) 1351 stmt.close(); 1352 } 1353 catch (Exception ignore) 1354 { 1355 } 1356 } 1357 } 1358 1359 1366 public ArrayList getCheckpointNames() throws SQLException 1367 { 1368 PreparedStatement stmt = null; 1369 1370 waitForLogQueueToEmpty(); 1371 1372 try 1373 { 1374 if (logger.isDebugEnabled()) 1375 logger.debug("Retrieving checkpoint names list"); 1376 stmt = getDatabaseConnection().prepareStatement( 1377 "SELECT name from " + checkpointTableName); 1378 ResultSet rs = stmt.executeQuery(); 1379 ArrayList list = new ArrayList (); 1380 while (rs.next()) 1381 { 1382 list.add(rs.getString(1)); 1383 } 1384 rs.close(); 1385 return list; 1386 } 1387 catch (Exception e) 1388 { 1389 invalidateInternalConnection(); 1390 throw new SQLException (Translate.get( 1391 "recovery.jdbc.checkpoint.list.failed", e)); 1392 } 1393 finally 1394 { 1395 try 1396 { 1397 if (stmt != null) 1398 stmt.close(); 1399 } 1400 catch (SQLException ignore) 1401 { 1402 } 1403 } 1404 } 1405 1406 1416 public long getCheckpointRequestId(String checkpointName) throws SQLException 1417 { 1418 long requestId = -1; 1419 PreparedStatement stmt = null; 1420 ResultSet rs = null; 1421 try 1422 { 1423 stmt = getDatabaseConnection().prepareStatement( 1424 "SELECT request_id FROM " + checkpointTableName 1425 + " WHERE name LIKE ?"); 1426 stmt.setString(1, checkpointName); 1427 rs = stmt.executeQuery(); 1428 1429 if (rs.next()) 1430 requestId = rs.getLong("request_id"); 1431 else 1432 { 1433 String msg = Translate.get("recovery.jdbc.checkpoint.not.found", 1434 checkpointName); 1435 logger.info(msg); 1436 throw new SQLException (msg); 1437 } 1438 } 1439 catch (SQLException e) 1440 { 1441 invalidateInternalConnection(); 1442 throw new SQLException (Translate.get( 1443 "recovery.jdbc.checkpoint.not.found.error", new String []{ 1444 checkpointName, e.getMessage()})); 1445 } 1446 finally 1447 { 1448 try 1449 { 1450 if (rs != null) 1451 rs.close(); 1452 } 1453 catch (Exception ignore) 1454 { 1455 } 1456 try 1457 { 1458 if (stmt != null) 1459 stmt.close(); 1460 } 1461 catch (Exception ignore) 1462 { 1463 } 1464 } 1465 return requestId; 1466 } 1467 1468 1475 public void removeCheckpoint(String checkpointName) throws SQLException 1476 { 1477 PreparedStatement stmt = null; 1478 1479 waitForLogQueueToEmpty(); 1480 1481 try 1482 { 1483 stmt = getDatabaseConnection().prepareStatement( 1485 "SELECT * FROM " + checkpointTableName + " WHERE name LIKE ?"); 1486 stmt.setString(1, checkpointName); 1487 ResultSet rs = stmt.executeQuery(); 1488 boolean checkpointExists = rs.next(); 1489 if (!checkpointExists) 1490 { 1491 rs.close(); 1492 stmt.close(); 1493 throw new SQLException ("Checkpoint " + checkpointName 1494 + " does not exist"); 1495 } 1496 1497 long requestId = rs.getLong("request_id"); 1498 rs.close(); 1499 stmt.close(); 1500 1501 stmt = getDatabaseConnection().prepareStatement( 1503 "DELETE FROM " + logTableName + " WHERE id <= ?"); 1504 stmt.setLong(1, requestId); 1505 stmt.executeUpdate(); 1506 stmt.close(); 1507 1508 stmt = getDatabaseConnection().prepareStatement( 1510 "DELETE FROM " + checkpointTableName + " WHERE name like ?"); 1511 stmt.setString(1, checkpointName); 1512 stmt.executeUpdate(); 1513 stmt.close(); 1514 } 1515 catch (SQLException e) 1516 { 1517 invalidateInternalConnection(); 1518 throw new SQLException (Translate.get( 1519 "recovery.jdbc.checkpoint.remove.failed", new String []{ 1520 checkpointName, e.getMessage()})); 1521 } 1522 finally 1523 { 1524 try 1525 { 1526 if (stmt != null) 1527 stmt.close(); 1528 } 1529 catch (Exception ignore) 1530 { 1531 } 1532 1533 } 1534 } 1535 1536 1543 public void storeBackendRecoveryInfo(String databaseName, 1544 BackendRecoveryInfo backendRecoveryInfo) throws SQLException 1545 { 1546 PreparedStatement stmt = null; 1547 PreparedStatement stmt2 = null; 1548 if ((backendRecoveryInfo.getCheckpoint() == null) 1549 || ((backendRecoveryInfo.getBackendState() != BackendState.DISABLED) && (backendRecoveryInfo 1550 .getBackendState() != BackendState.UNKNOWN))) 1551 backendRecoveryInfo.setCheckpoint(""); else 1553 { getCheckpointRequestId(backendRecoveryInfo.getCheckpoint()); 1555 } 1556 1557 try 1558 { 1559 stmt = getDatabaseConnection().prepareStatement( 1561 "SELECT * FROM " + backendTableName 1562 + " WHERE backend_name LIKE ? and database_name LIKE ?"); 1563 stmt.setString(1, backendRecoveryInfo.getBackendName()); 1564 stmt.setString(2, databaseName); 1565 ResultSet rs = stmt.executeQuery(); 1566 boolean mustUpdate = rs.next(); 1567 rs.close(); 1568 if (!mustUpdate) 1569 { 1570 stmt2 = getDatabaseConnection().prepareStatement( 1571 "INSERT INTO " + backendTableName + " values(?,?,?,?)"); 1572 stmt2.setString(1, databaseName); 1573 stmt2.setString(2, backendRecoveryInfo.getBackendName()); 1574 stmt2.setInt(3, backendRecoveryInfo.getBackendState()); 1575 stmt2.setString(4, backendRecoveryInfo.getCheckpoint()); 1576 if (stmt2.executeUpdate() != 1) 1577 throw new SQLException ( 1578 "Error while inserting new backend reference. Incorrect number of rows"); 1579 } 1580 else 1581 { 1582 stmt2 = getDatabaseConnection() 1583 .prepareStatement( 1584 "UPDATE " 1585 + backendTableName 1586 + " set backend_state=?,checkpoint_name=? where backend_name=? and database_name=?"); 1587 stmt2.setInt(1, backendRecoveryInfo.getBackendState()); 1588 stmt2.setString(2, backendRecoveryInfo.getCheckpoint()); 1589 stmt2.setString(3, backendRecoveryInfo.getBackendName()); 1590 stmt2.setString(4, databaseName); 1591 if (stmt2.executeUpdate() != 1) 1592 throw new SQLException ( 1593 "Error while updating backend reference. Incorrect number of rows"); 1594 } 1595 } 1596 catch (SQLException e) 1597 { 1598 invalidateInternalConnection(); 1599 1600 logger.warn("Failed to store backend recovery info", e); 1601 1602 throw new SQLException ("Unable to update checkpoint '" 1603 + backendRecoveryInfo.getCheckpoint() + "' for backend:" 1604 + backendRecoveryInfo.getBackendName()); 1605 } 1606 finally 1607 { 1608 try 1609 { 1610 if (stmt != null) 1611 stmt.close(); 1612 } 1613 catch (Exception ignore) 1614 { 1615 } 1616 try 1617 { 1618 if (stmt2 != null) 1619 stmt2.close(); 1620 } 1621 catch (Exception ignore) 1622 { 1623 } 1624 } 1625 } 1626 1627 1633 public void storeCheckpoint(String checkpointName) throws SQLException 1634 { 1635 storeCheckpoint(checkpointName, logTableId); 1636 } 1637 1638 1645 public void storeCheckpoint(String checkpointName, long requestId) 1646 throws SQLException 1647 { 1648 PreparedStatement stmt = null; 1649 1650 if (!validCheckpointName(checkpointName)) 1652 { 1653 throw new SQLException (Translate.get( 1654 "recovery.jdbc.checkpoint.duplicate", checkpointName)); 1655 } 1656 1657 waitForLogQueueToEmpty(); 1658 1659 try 1660 { 1661 if (logger.isDebugEnabled()) 1662 logger.debug("Storing checkpoint " + checkpointName + " at request id " 1663 + requestId); 1664 stmt = getDatabaseConnection().prepareStatement( 1665 "INSERT INTO " + checkpointTableName + " VALUES(?,?)"); 1666 stmt.setString(1, checkpointName); 1667 stmt.setLong(2, requestId); 1668 stmt.executeUpdate(); 1669 } 1670 catch (SQLException e) 1671 { 1672 invalidateInternalConnection(); 1673 throw new SQLException (Translate.get( 1674 "recovery.jdbc.checkpoint.store.failed", new String []{checkpointName, 1675 e.getMessage()})); 1676 } 1677 finally 1678 { 1679 try 1680 { 1681 if (stmt != null) 1682 stmt.close(); 1683 } 1684 catch (Exception ignore) 1685 { 1686 } 1687 } 1688 } 1689 1690 1696 1704 public DumpInfo getDumpInfo(String dumpName) throws SQLException 1705 { 1706 PreparedStatement stmt = null; 1707 1708 try 1709 { 1710 if (logger.isDebugEnabled()) 1711 logger.debug("Retrieving dump " + dumpName + " information"); 1712 stmt = getDatabaseConnection().prepareStatement( 1713 "SELECT * from " + dumpTableName + " WHERE dump_name LIKE ?"); 1714 stmt.setString(1, dumpName); 1715 1716 ResultSet rs = stmt.executeQuery(); 1717 DumpInfo dumpInfo = null; 1718 if (rs.next()) 1719 { 1720 dumpInfo = new DumpInfo(rs.getString("dump_name"), rs 1721 .getString("dump_date"), rs.getString("dump_path"), rs 1722 .getString("dump_format"), rs.getString("checkpoint_name"), rs 1723 .getString("backend_name"), rs.getString(dumpTableTablesColumnName)); 1724 } 1725 1727 rs.close(); 1728 return dumpInfo; 1729 } 1730 catch (Exception e) 1731 { 1732 invalidateInternalConnection(); 1733 throw new SQLException (Translate.get("recovery.jdbc.dump.info.failed", 1734 new String []{dumpName, e.getMessage()})); 1735 } 1736 finally 1737 { 1738 try 1739 { 1740 if (stmt != null) 1741 stmt.close(); 1742 } 1743 catch (SQLException ignore) 1744 { 1745 } 1746 } 1747 } 1748 1749 1755 public ArrayList getDumpList() throws SQLException 1756 { 1757 PreparedStatement stmt = null; 1758 1759 try 1760 { 1761 if (logger.isDebugEnabled()) 1762 logger.debug("Retrieving dump list"); 1763 stmt = getDatabaseConnection().prepareStatement( 1764 "SELECT * FROM " + dumpTableName + " ORDER BY dump_date DESC"); 1765 ResultSet rs = stmt.executeQuery(); 1766 ArrayList list = new ArrayList (); 1767 while (rs.next()) 1768 { 1769 list 1770 .add(new DumpInfo(rs.getString("dump_name"), rs 1771 .getString("dump_date"), rs.getString("dump_path"), rs 1772 .getString("dump_format"), rs.getString("checkpoint_name"), rs 1773 .getString("backend_name"), rs 1774 .getString(dumpTableTablesColumnName))); 1775 } 1776 rs.close(); 1777 return list; 1778 } 1779 catch (Exception e) 1780 { 1781 invalidateInternalConnection(); 1782 throw new SQLException (Translate.get("recovery.jdbc.dump.list.failed", e)); 1783 } 1784 finally 1785 { 1786 try 1787 { 1788 if (stmt != null) 1789 stmt.close(); 1790 } 1791 catch (SQLException ignore) 1792 { 1793 } 1794 } 1795 } 1796 1797 1804 public void removeDump(DumpInfo dumpInfo) throws SQLException 1805 { 1806 PreparedStatement stmt = null; 1807 1808 try 1809 { 1810 if (logger.isDebugEnabled()) 1811 { 1812 logger.debug("removing dump " + dumpInfo.getDumpName()); 1813 } 1814 stmt = getDatabaseConnection().prepareStatement( 1815 "DELETE FROM " + dumpTableName + " WHERE dump_name=?"); 1816 stmt.setString(1, dumpInfo.getDumpName()); 1817 1818 stmt.executeUpdate(); 1819 } 1820 catch (Exception e) 1821 { 1822 invalidateInternalConnection(); 1823 throw new SQLException (Translate.get("recovery.jdbc.dump.remove.failed", 1824 new String []{dumpInfo.getDumpName(), e.getMessage()})); 1825 } 1826 finally 1827 { 1828 try 1829 { 1830 if (stmt != null) 1831 stmt.close(); 1832 } 1833 catch (SQLException ignore) 1834 { 1835 } 1836 } 1837 } 1838 1839 1845 public void setDumpInfo(DumpInfo dumpInfo) throws VirtualDatabaseException 1846 { 1847 try 1848 { 1849 storeDump(dumpInfo); 1850 } 1851 catch (SQLException e) 1852 { 1853 throw new VirtualDatabaseException(e); 1854 } 1855 } 1856 1857 1863 public void storeDump(DumpInfo dump) throws SQLException 1864 { 1865 PreparedStatement stmt = null; 1866 1867 if (dump == null) 1868 throw new NullPointerException ( 1869 "Invalid null dump in JDBCRecoverylog.storeDump"); 1870 1871 try 1872 { 1873 if (logger.isDebugEnabled()) 1874 logger.debug("Storing dump " + dump.getDumpName()); 1875 stmt = getDatabaseConnection().prepareStatement( 1876 "INSERT INTO " + dumpTableName + " VALUES (?,?,?,?,?,?,?)"); 1877 stmt.setString(1, dump.getDumpName()); 1878 stmt.setString(2, dump.getDumpDate()); 1879 stmt.setString(3, dump.getDumpPath()); 1880 stmt.setString(4, dump.getDumpFormat()); 1881 stmt.setString(5, dump.getCheckpointName()); 1882 stmt.setString(6, dump.getBackendName()); 1883 stmt.setString(7, dump.getTables()); 1884 1885 stmt.executeUpdate(); 1886 } 1887 catch (Exception e) 1888 { 1889 invalidateInternalConnection(); 1890 throw new SQLException (Translate.get("recovery.jdbc.dump.store.failed", 1891 new String []{dump.getDumpName(), e.getMessage()})); 1892 } 1893 finally 1894 { 1895 try 1896 { 1897 if (stmt != null) 1898 stmt.close(); 1899 } 1900 catch (SQLException ignore) 1901 { 1902 } 1903 } 1904 } 1905 1906 1915 public boolean updateDumpPath(String dumpName, String newPath) 1916 throws SQLException 1917 { 1918 DumpInfo dumpInfo = getDumpInfo(dumpName); 1919 if (dumpInfo == null) 1920 return false; 1921 1922 PreparedStatement stmt = null; 1923 1924 try 1925 { 1926 if (logger.isDebugEnabled()) 1927 logger.debug("Changing old path " + dumpInfo.getDumpPath() 1928 + " for dump " + dumpInfo.getDumpName() + " to " + newPath); 1929 stmt = getDatabaseConnection().prepareStatement( 1930 "UPDATE " + dumpTableName + " SET dump_path=? WHERE dump_name=?"); 1931 stmt.setString(1, newPath); 1932 stmt.setString(2, dumpName); 1933 1934 return stmt.executeUpdate() == 1; 1935 } 1936 catch (Exception e) 1937 { 1938 invalidateInternalConnection(); 1939 throw new SQLException (Translate.get( 1940 "recovery.jdbc.dump.update.path.failed", new String []{dumpName, 1941 e.getMessage()})); 1942 } 1943 finally 1944 { 1945 try 1946 { 1947 if (stmt != null) 1948 stmt.close(); 1949 } 1950 catch (SQLException ignore) 1951 { 1952 } 1953 } 1954 } 1955 1956 1962 1966 public void checkRecoveryLogTables() 1967 { 1968 try 1969 { 1970 intializeDatabase(); 1971 } 1972 catch (SQLException e) 1973 { 1974 throw new RuntimeException ("Unable to initialize the database: " + e); 1975 } 1976 1977 loggerThread = new LoggerThread(this); 1979 loggerThread.start(); 1980 } 1981 1982 1987 public String getBackendTableName() 1988 { 1989 return backendTableName; 1990 } 1991 1992 1997 public String getCheckpointTableName() 1998 { 1999 return checkpointTableName; 2000 } 2001 2002 2007 public String getLogTableName() 2008 { 2009 return logTableName; 2010 } 2011 2012 2017 public String getLogTableSqlColumnName() 2018 { 2019 return logTableSqlColumnName; 2020 } 2021 2022 2033 public void setBackendTableCreateStatement(String createTable, 2034 String tableName, String checkpointNameType, String backendNameType, 2035 String backendStateType, String databaseNameType, String extraStatement) 2036 { 2037 this.backendTableCreateTable = createTable; 2038 this.backendTableName = tableName; 2039 this.backendTableDatabaseName = databaseNameType; 2040 this.backendTableBackendName = backendNameType; 2041 this.backendTableBackendState = backendStateType; 2042 this.backendTableCheckpointName = checkpointNameType; 2043 this.backendTableExtraStatement = extraStatement; 2044 this.backendTableCreateStatement = createTable + " " + backendTableName 2045 + " (database_name " + databaseNameType + ", backend_name " 2046 + backendNameType + ",backend_state " + backendStateType 2047 + ", checkpoint_name " + checkpointNameType + " " + extraStatement 2048 + ")"; 2049 2050 if (logger.isDebugEnabled()) 2051 logger.debug(Translate.get("recovery.jdbc.backendtable.statement", 2052 backendTableCreateStatement)); 2053 } 2054 2055 2064 public void setCheckpointTableCreateStatement(String createTable, 2065 String tableName, String nameType, String requestIdType, 2066 String extraStatement) 2067 { 2068 this.checkpointTableCreateTable = createTable; 2069 this.checkpointTableName = tableName; 2070 this.checkpointTableNameType = nameType; 2071 this.checkpointTableRequestIdType = requestIdType; 2072 this.checkpointTableExtraStatement = extraStatement; 2073 2078 checkpointTableCreateStatement = createTable + " " + tableName + " (name " 2079 + nameType + ",request_id " + requestIdType + extraStatement + ")"; 2080 if (logger.isDebugEnabled()) 2081 logger.debug(Translate.get("recovery.jdbc.checkpointtable.statement", 2082 checkpointTableCreateStatement)); 2083 } 2084 2085 2100 public void setDumpTableCreateStatement(String createTable, String tableName, 2101 String dumpNameColumnType, String dumpDateColumnType, 2102 String dumpPathColumnType, String dumpFormatColumnType, 2103 String checkpointNameColumnType, String backendNameColumnType, 2104 String tablesColumnName, String tablesColumnType, String extraStatement) 2105 { 2106 this.dumpTableCreateTable = createTable; 2107 this.dumpTableName = tableName; 2108 this.dumpTableDumpNameColumnType = dumpNameColumnType; 2109 this.dumpTableDumpDateColumnType = dumpDateColumnType; 2110 this.dumpTableDumpPathColumnType = dumpPathColumnType; 2111 this.dumpTableDumpFormatColumnType = dumpFormatColumnType; 2112 this.dumpTableCheckpointNameColumnType = checkpointNameColumnType; 2113 this.dumpTableBackendNameColumnType = backendNameColumnType; 2114 this.dumpTableTablesColumnName = tablesColumnName; 2115 this.dumpTableTablesColumnType = tablesColumnType; 2116 this.dumpTableExtraStatementDefinition = extraStatement; 2117 2118 2128 dumpTableCreateStatement = dumpTableCreateTable + " " + dumpTableName 2129 + " (dump_name " + dumpTableDumpNameColumnType + ",dump_date " 2130 + dumpDateColumnType + ",dump_path " + dumpPathColumnType 2131 + ",dump_format " + dumpFormatColumnType + ",checkpoint_name " 2132 + checkpointNameColumnType + ",backend_name " + backendNameColumnType 2133 + "," + dumpTableTablesColumnName + " " + tablesColumnType 2134 + extraStatement + ")"; 2135 if (logger.isDebugEnabled()) 2136 logger.debug(Translate.get("recovery.jdbc.dumptable.statement", 2137 dumpTableCreateStatement)); 2138 } 2139 2140 2152 public void setLogTableCreateStatement(String createTable, String tableName, 2153 String idType, String vloginType, String sqlName, String sqlType, 2154 String transactionIdType, String extraStatement) 2155 { 2156 this.logTableCreateTable = createTable; 2157 this.logTableName = tableName; 2158 this.logTableIdType = idType; 2159 this.logTableVloginType = vloginType; 2160 this.logTableSqlColumnName = sqlName; 2161 this.logTableSqlType = sqlType; 2162 this.logTableTransactionIdType = transactionIdType; 2163 this.logTableExtraStatement = extraStatement; 2164 logTableCreateStatement = createTable + " " + tableName + " (id " + idType 2165 + ",vlogin " + vloginType + "," + logTableSqlColumnName + " " + sqlType 2166 + ",transaction_id " + transactionIdType + extraStatement + ")"; 2167 if (logger.isDebugEnabled()) 2168 logger.debug(Translate.get("recovery.jdbc.logtable.statement", 2169 logTableCreateStatement)); 2170 } 2171 2172 2178 2186 private String recreateSkeleton(String sql) 2187 { 2188 StringBuffer skeleton = new StringBuffer (); 2191 int start = 0; 2192 int end; 2193 while ((end = sql.indexOf( 2194 org.objectweb.cjdbc.driver.PreparedStatement.START_PARAM_TAG, start)) != -1) 2195 { 2196 skeleton.append(sql.substring(start, end)).append('?'); 2197 start = sql.indexOf( 2198 org.objectweb.cjdbc.driver.PreparedStatement.END_PARAM_TAG, end); 2199 if (start == -1) 2200 throw new RuntimeException ("Malformed query in recovery log: " + sql); 2201 else 2202 start += org.objectweb.cjdbc.driver.PreparedStatement.END_PARAM_TAG 2203 .length(); 2204 } 2205 if (start < sql.length()) 2206 skeleton.append(sql.substring(start)); 2207 return skeleton.toString(); 2208 } 2209 2210 2216 private void setDriverProcessedAndSkeleton(AbstractRequest request) 2217 { 2218 String sql = request.getSQL(); 2219 boolean isDriverProcessed = sql 2220 .indexOf(org.objectweb.cjdbc.driver.PreparedStatement.END_PARAM_TAG) == -1; 2221 request.setDriverProcessed(isDriverProcessed); 2222 if (isDriverProcessed) 2223 return; 2225 request.setSqlSkeleton(recreateSkeleton(sql)); 2226 } 2227 2228 2235 private boolean validCheckpointName(String checkpointName) 2236 throws SQLException 2237 { 2238 PreparedStatement stmt = null; 2239 ResultSet rs = null; 2240 try 2241 { 2242 stmt = getDatabaseConnection().prepareStatement( 2243 "SELECT * FROM " + checkpointTableName + " WHERE name LIKE ?"); 2244 stmt.setString(1, checkpointName); 2245 rs = stmt.executeQuery(); 2246 2247 boolean checkpointExists = rs.next(); 2250 rs.close(); 2251 return !checkpointExists; 2252 } 2253 catch (SQLException e) 2254 { 2255 invalidateInternalConnection(); 2256 throw new SQLException (Translate.get( 2257 "recovery.jdbc.checkpoint.check.failed", e)); 2258 } 2259 finally 2260 { 2261 try 2262 { 2263 if (stmt != null) 2264 stmt.close(); 2265 } 2266 catch (SQLException ignore) 2267 { 2268 } 2269 } 2270 } 2271 2272 2276 private void waitForLogQueueToEmpty() 2277 { 2278 synchronized (loggerThread) 2279 { 2280 while (!loggerThread.getLogQueueIsEmpty()) 2281 { 2282 try 2283 { 2284 loggerThread.wait(); 2285 } 2286 catch (Exception e) 2287 { 2288 logger.warn("Exception " + e 2289 + " while waiting for end of transactions"); 2290 } 2291 } 2292 } 2293 } 2294 2295 2301 2304 public String getAssociatedString() 2305 { 2306 return "jdbcrecoverylog"; 2307 } 2308 2309 2315 public String [][] getData() 2316 { 2317 Statement stmt = null; 2318 ResultSet rs = null; 2319 try 2320 { 2321 stmt = getDatabaseConnection().createStatement(); 2322 rs = stmt.executeQuery("select * from " + logTableName); 2323 ArrayList list = new ArrayList (); 2324 while (rs.next()) 2325 { 2326 list.add(new String []{rs.getString(3), rs.getString(2), 2328 rs.getString(1), rs.getString(4)}); 2329 } 2330 String [][] result = new String [list.size()][4]; 2331 for (int i = 0; i < list.size(); i++) 2332 result[i] = (String []) list.get(i); 2333 return result; 2334 } 2335 catch (SQLException e) 2336 { 2337 return null; 2338 } 2339 finally 2340 { 2341 try 2342 { 2343 rs.close(); 2344 } 2345 catch (SQLException ignore) 2346 { 2347 } 2348 try 2349 { 2350 stmt.close(); 2351 } 2352 catch (SQLException ignore) 2353 { 2354 } 2355 } 2356 } 2357 2358 2361 public String getXml() 2362 { 2363 StringBuffer info = new StringBuffer (); 2364 info.append("<" + DatabasesXmlTags.ELT_RecoveryLog + " " 2365 + DatabasesXmlTags.ATT_driver + "=\"" + driverClassName + "\" " 2366 + DatabasesXmlTags.ATT_url + "=\"" + url + "\" "); 2367 if (driverName != null) 2368 { 2369 info.append(DatabasesXmlTags.ATT_driverPath + "=\"" + driverName + "\" "); 2370 } 2371 info.append(DatabasesXmlTags.ATT_login + "=\"" + login + "\" " 2372 + DatabasesXmlTags.ATT_password + "=\"" + password + "\" " 2373 + DatabasesXmlTags.ATT_requestTimeout + "=\"" + (timeout / 1000) 2374 + "\" " + DatabasesXmlTags.ATT_recoveryBatchSize + "=\"" 2375 + recoveryBatchSize + "\">"); 2376 info.append("<" + DatabasesXmlTags.ELT_RecoveryLogTable + " " 2378 + DatabasesXmlTags.ATT_createTable + "=\"" + logTableCreateTable 2379 + "\" " + DatabasesXmlTags.ATT_tableName + "=\"" + logTableName + "\" " 2380 + DatabasesXmlTags.ATT_idColumnType + "=\"" + logTableIdType + "\" " 2381 + DatabasesXmlTags.ATT_vloginColumnType + "=\"" + logTableVloginType 2382 + "\" " + DatabasesXmlTags.ATT_sqlColumnType + "=\"" + logTableSqlType 2383 + "\" " + DatabasesXmlTags.ATT_transactionIdColumnType + "=\"" 2384 + logTableTransactionIdType + "\" " 2385 + DatabasesXmlTags.ATT_extraStatementDefinition + "=\"" 2386 + logTableExtraStatement + "\"/>"); 2387 info.append("<" + DatabasesXmlTags.ELT_CheckpointTable + " " 2389 + DatabasesXmlTags.ATT_createTable + "=\"" + checkpointTableCreateTable 2390 + "\" " + DatabasesXmlTags.ATT_tableName + "=\"" + checkpointTableName 2391 + "\" " + DatabasesXmlTags.ATT_checkpointNameColumnType + "=\"" 2392 + checkpointTableNameType + "\" " 2393 + DatabasesXmlTags.ATT_requestIdColumnType + "=\"" 2394 + checkpointTableRequestIdType + "\" " 2395 + DatabasesXmlTags.ATT_extraStatementDefinition + "=\"" 2396 + checkpointTableExtraStatement + "\"" + "/>"); 2397 info.append("<" + DatabasesXmlTags.ELT_BackendTable + " " 2399 + DatabasesXmlTags.ATT_createTable + "=\"" + backendTableCreateTable 2400 + "\" " + DatabasesXmlTags.ATT_tableName + "=\"" + backendTableName 2401 + "\" " + DatabasesXmlTags.ATT_databaseNameColumnType + "=\"" 2402 + backendTableDatabaseName + "\" " 2403 + DatabasesXmlTags.ATT_backendNameColumnType + "=\"" 2404 + backendTableBackendName + "\" " 2405 + DatabasesXmlTags.ATT_backendStateColumnType + "=\"" 2406 + backendTableBackendState + "\" " 2407 + DatabasesXmlTags.ATT_checkpointNameColumnType + "=\"" 2408 + backendTableCheckpointName + "\" " 2409 + DatabasesXmlTags.ATT_extraStatementDefinition + "=\"" 2410 + backendTableExtraStatement + "\"" + "/>"); 2411 info.append("<" + DatabasesXmlTags.ELT_DumpTable + " " 2413 + DatabasesXmlTags.ATT_createTable + "=\"" + dumpTableCreateTable 2414 + "\" " + DatabasesXmlTags.ATT_tableName + "=\"" + dumpTableName 2415 + "\" " + DatabasesXmlTags.ATT_dumpNameColumnType + "=\"" 2416 + dumpTableDumpNameColumnType + "\" " 2417 + DatabasesXmlTags.ATT_dumpDateColumnType + "=\"" 2418 + dumpTableDumpDateColumnType + "\" " 2419 + DatabasesXmlTags.ATT_dumpPathColumnType + "=\"" 2420 + dumpTableDumpPathColumnType + "\" " 2421 + DatabasesXmlTags.ATT_dumpFormatColumnType + "=\"" 2422 + dumpTableDumpFormatColumnType + "\" " 2423 + DatabasesXmlTags.ATT_checkpointNameColumnType + "=\"" 2424 + dumpTableCheckpointNameColumnType + "\" " 2425 + DatabasesXmlTags.ATT_backendNameColumnType + "=\"" 2426 + dumpTableBackendNameColumnType + "\" " 2427 + DatabasesXmlTags.ATT_tablesColumnName + "=\"" 2428 + dumpTableTablesColumnName + "\" " 2429 + DatabasesXmlTags.ATT_tablesColumnType + "=\"" 2430 + dumpTableTablesColumnType + "\" " 2431 + DatabasesXmlTags.ATT_extraStatementDefinition + "=\"" 2432 + dumpTableExtraStatementDefinition + "\"" + "/>"); 2433 info.append("</" + DatabasesXmlTags.ELT_RecoveryLog + ">"); 2434 2435 return info.toString(); 2436 } 2437 2438 2443 public void storeDumpCheckpointName(String dumpCheckpointName, 2444 long checkpointId) 2445 { 2446 loggerThread.log(new StoreDumpCheckpointEvent(dumpCheckpointName, 2447 checkpointId)); 2448 } 2449 2450} | Popular Tags |