1 24 25 package org.continuent.sequoia.controller.virtualdatabase; 26 27 import java.sql.SQLException ; 28 import java.sql.SQLWarning ; 29 import java.text.SimpleDateFormat ; 30 import java.util.ArrayList ; 31 import java.util.ConcurrentModificationException ; 32 import java.util.Date ; 33 import java.util.Iterator ; 34 import java.util.LinkedList ; 35 import java.util.List ; 36 import java.util.Map ; 37 38 import javax.management.MalformedObjectNameException ; 39 import javax.management.Notification ; 40 import javax.management.NotificationBroadcasterSupport ; 41 import javax.management.ObjectName ; 42 43 import org.continuent.sequoia.common.exceptions.BackupException; 44 import org.continuent.sequoia.common.exceptions.NoMoreBackendException; 45 import org.continuent.sequoia.common.exceptions.VirtualDatabaseException; 46 import org.continuent.sequoia.common.i18n.Translate; 47 import org.continuent.sequoia.common.jmx.JmxConstants; 48 import org.continuent.sequoia.common.jmx.management.BackendInfo; 49 import org.continuent.sequoia.common.jmx.management.BackendState; 50 import org.continuent.sequoia.common.jmx.management.DumpInfo; 51 import org.continuent.sequoia.common.jmx.monitoring.backend.BackendStatistics; 52 import org.continuent.sequoia.common.jmx.notifications.SequoiaNotificationList; 53 import org.continuent.sequoia.common.log.Trace; 54 import org.continuent.sequoia.common.users.AdminUser; 55 import org.continuent.sequoia.common.users.VirtualDatabaseUser; 56 import org.continuent.sequoia.common.util.Constants; 57 import org.continuent.sequoia.common.xml.DatabasesXmlTags; 58 import org.continuent.sequoia.common.xml.XmlComponent; 59 import org.continuent.sequoia.controller.authentication.AuthenticationManager; 60 import org.continuent.sequoia.controller.backend.DatabaseBackend; 61 import org.continuent.sequoia.controller.backend.result.ControllerResultSet; 62 import org.continuent.sequoia.controller.backend.result.ExecuteResult; 63 import org.continuent.sequoia.controller.backend.result.ExecuteUpdateResult; 64 import org.continuent.sequoia.controller.backend.result.GeneratedKeysResult; 65 import org.continuent.sequoia.controller.backup.Backuper; 66 import org.continuent.sequoia.controller.cache.result.AbstractResultCache; 67 import org.continuent.sequoia.controller.core.Controller; 68 import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseForceShutdownThread; 69 import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseSafeShutdownThread; 70 import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseShutdownThread; 71 import org.continuent.sequoia.controller.core.shutdown.VirtualDatabaseWaitShutdownThread; 72 import org.continuent.sequoia.controller.jmx.MBeanServerManager; 73 import org.continuent.sequoia.controller.loadbalancer.AllBackendsFailedException; 74 import org.continuent.sequoia.controller.locks.ReadPrioritaryFIFOWriteLock; 75 import org.continuent.sequoia.controller.monitoring.SQLMonitoring; 76 import org.continuent.sequoia.controller.recoverylog.BackendRecoveryInfo; 77 import org.continuent.sequoia.controller.recoverylog.RecoverThread; 78 import org.continuent.sequoia.controller.recoverylog.RecoveryLog; 79 import org.continuent.sequoia.controller.requestmanager.RAIDbLevels; 80 import org.continuent.sequoia.controller.requestmanager.RequestManager; 81 import org.continuent.sequoia.controller.requests.AbstractRequest; 82 import org.continuent.sequoia.controller.requests.AbstractWriteRequest; 83 import org.continuent.sequoia.controller.requests.SelectRequest; 84 import org.continuent.sequoia.controller.requests.StoredProcedure; 85 import org.continuent.sequoia.controller.semantic.SemanticManager; 86 import org.continuent.sequoia.controller.sql.schema.DatabaseSchema; 87 import org.continuent.sequoia.controller.sql.schema.DynamicDatabaseSchema; 88 import org.continuent.sequoia.controller.virtualdatabase.management.AbstractAdminOperation; 89 import org.continuent.sequoia.controller.virtualdatabase.management.BackupBackendOperation; 90 import org.continuent.sequoia.controller.virtualdatabase.management.EnableBackendOperation; 91 import org.continuent.sequoia.controller.virtualdatabase.management.RestoreDumpOperation; 92 93 107 public class VirtualDatabase implements XmlComponent 108 { 109 private static final long serialVersionUID = 1399418136380336827L; 110 111 124 125 protected String name; 126 127 131 protected AuthenticationManager authenticationManager; 132 133 134 protected ArrayList backends; 135 136 137 protected ReadPrioritaryFIFOWriteLock rwLock; 138 139 140 protected RequestManager requestManager; 141 142 143 protected DynamicDatabaseSchema dynamicDatabaseSchema; 144 145 146 protected SemanticManager semanticManager = new SemanticManager(); 147 148 149 protected LinkedList totalOrderQueue = null; 150 151 152 protected Trace logger = null; 153 protected Trace requestLogger = null; 154 155 156 static Trace endUserLogger = Trace 157 .getLogger("org.continuent.sequoia.enduser"); 158 159 private ArrayList activeThreads = new ArrayList (); 161 private int idleThreads = 0; 163 private ArrayList pendingConnections = new ArrayList (); 165 166 167 protected int maxNbOfConnections; 168 169 170 protected boolean poolConnectionThreads; 171 172 173 protected long maxThreadIdleTime; 174 175 179 protected int minNbOfThreads; 180 181 182 protected int maxNbOfThreads; 183 184 185 protected int currentNbOfThreads; 186 187 188 protected VirtualDatabaseDynamicMetaData metadata; 189 private boolean useStaticResultSetMetaData = true; 190 protected VirtualDatabaseStaticMetaData staticMetadata; 191 192 private SQLMonitoring sqlMonitor = null; 193 194 195 public static final int CHECK_BACKEND_ENABLE = 1; 196 197 public static final int CHECK_BACKEND_DISABLE = 0; 198 199 public static final int NO_CHECK_BACKEND = -1; 200 201 202 private int sqlShortFormLength; 203 204 205 Controller controller; 206 207 208 private String databaseProductNames = "Sequoia"; 209 210 211 protected boolean shuttingDown = false; 212 private boolean refusingNewTransaction = false; 213 214 private List currentAdminOperations; 215 216 protected NotificationBroadcasterSupport notificationBroadcasterSupport; 217 218 protected int notificationSequence = 0; 219 220 protected long connectionId = 0; 221 222 239 public VirtualDatabase(Controller controller, String name, 240 int maxConnections, boolean pool, int minThreads, int maxThreads, 241 long maxThreadIdleTime, int sqlShortFormLength, 242 boolean useStaticResultSetMetaData) 243 { 244 this.controller = controller; 245 this.name = name; 246 this.maxNbOfConnections = maxConnections; 247 this.poolConnectionThreads = pool; 248 this.minNbOfThreads = minThreads; 249 this.maxNbOfThreads = maxThreads; 250 this.maxThreadIdleTime = maxThreadIdleTime; 251 this.sqlShortFormLength = sqlShortFormLength; 252 this.useStaticResultSetMetaData = useStaticResultSetMetaData; 253 backends = new ArrayList (); 254 currentAdminOperations = new LinkedList (); 255 256 rwLock = new ReadPrioritaryFIFOWriteLock(); 257 logger = Trace 258 .getLogger("org.continuent.sequoia.controller.virtualdatabase." + name); 259 requestLogger = Trace 260 .getLogger("org.continuent.sequoia.controller.virtualdatabase.request." 261 + name); 262 } 263 264 271 public void setNotificationBroadcasterSupport( 272 NotificationBroadcasterSupport notificationBroadcasterSupport) 273 { 274 this.notificationBroadcasterSupport = notificationBroadcasterSupport; 275 } 276 277 285 protected void sendJmxNotification(String type, String message) 286 { 287 try 288 { 289 notificationBroadcasterSupport.sendNotification(new Notification (type, 290 JmxConstants.getVirtualDataBaseObjectName(name), 291 notificationSequence++, message)); 292 } 293 catch (MalformedObjectNameException e) 294 { 295 logger.warn("Unable to send JMX notification", e); 297 } 298 } 299 300 307 public final void acquireReadLockBackendLists() throws InterruptedException 308 { 309 rwLock.acquireRead(); 310 } 311 312 317 public final void releaseReadLockBackendLists() 318 { 319 rwLock.releaseRead(); 320 } 321 322 327 public boolean isDistributed() 328 { 329 return false; 330 } 331 332 333 334 343 public boolean checkUserAuthentication(String virtualLogin, 344 String virtualPassword) 345 { 346 if (authenticationManager == null) 347 { 348 logger.error("No authentification manager defined to check login '" 349 + virtualLogin + "'"); 350 return false; 351 } 352 else 353 { 354 boolean result = authenticationManager 355 .isValidVirtualUser(new VirtualDatabaseUser(virtualLogin, 356 virtualPassword)); 357 if (!result) 358 endUserLogger.error(Translate.get( 359 "virtualdatabase.authentication.failed", virtualLogin)); 360 return result; 361 } 362 } 363 364 373 public boolean checkAdminAuthentication(String adminLogin, 374 String adminPassword) 375 { 376 if (authenticationManager == null) 377 { 378 endUserLogger.info(Translate.get( 379 "virtualdatabase.checking.authentication", new String []{adminLogin, 380 this.getVirtualDatabaseName()})); 381 String msg = "No authentification manager defined to check admin login '" 382 + adminLogin + "'"; 383 logger.error(msg); 384 endUserLogger.error(Translate.get( 385 "virtualdatabase.check.authentication.failed", new String []{ 386 adminLogin, this.getVirtualDatabaseName(), msg})); 387 return false; 388 } 389 else 390 { 391 boolean result = authenticationManager.isValidAdminUser(new AdminUser( 392 adminLogin, adminPassword)); 393 if (!result) 394 endUserLogger.error(Translate.get( 395 "virtualdatabase.authentication.failed", adminLogin)); 396 return result; 397 } 398 } 399 400 407 public void checkAndAddVirtualDatabaseUser(VirtualDatabaseUser vdbUser) 408 { 409 if (!isValidUserForAllBackends(vdbUser)) 411 { 412 if (logger.isWarnEnabled()) 413 { 414 logger.warn("Could not create new vdb user " + vdbUser.getLogin() 415 + " because it does not exist on all backends"); 416 } 417 return; 418 } 419 420 try 422 { 423 performAddVirtualDatabaseUser(vdbUser); 424 if (logger.isInfoEnabled()) 425 { 426 logger.info("Added new vdb user " + vdbUser.getLogin()); 427 } 428 } 429 catch (SQLException e) 430 { 431 if (logger.isWarnEnabled()) 432 { 433 logger.warn("Problem when adding default connection manager for user " 434 + vdbUser.getLogin() + ", trying to clean-up..."); 435 removeVirtualDatabaseUser(vdbUser); 436 } 437 } 438 } 439 440 445 private void removeVirtualDatabaseUser(VirtualDatabaseUser vdbUser) 446 { 447 performRemoveVirtualDatabaseUser(vdbUser); 448 } 449 450 457 public void performAddVirtualDatabaseUser(VirtualDatabaseUser vdbUser) 458 throws SQLException 459 { 460 for (Iterator iter = backends.iterator(); iter.hasNext();) 461 { 462 DatabaseBackend backend = (DatabaseBackend) iter.next(); 463 backend.addDefaultConnectionManager(vdbUser); 464 } 465 authenticationManager.addVirtualUser(vdbUser); 466 } 468 469 474 public void performRemoveVirtualDatabaseUser(VirtualDatabaseUser vdbUser) 475 { 476 authenticationManager.removeVirtualUser(vdbUser); 477 for (Iterator iter = backends.iterator(); iter.hasNext();) 478 { 479 DatabaseBackend backend = (DatabaseBackend) iter.next(); 480 try 481 { 482 backend.removeConnectionManager(vdbUser); 483 } 484 catch (SQLException e) 485 { 486 if (logger.isWarnEnabled()) 487 { 488 logger 489 .warn("Problem when removing default connection manager for user " 490 + vdbUser.getLogin()); 491 } 492 } 493 } 494 if (logger.isInfoEnabled()) 495 { 496 logger.info("Removed vdb user " + vdbUser.getLogin()); 497 } 498 } 499 500 506 public boolean isValidUserForAllBackends(VirtualDatabaseUser vdbUser) 507 { 508 boolean result = true; 509 for (Iterator iter = backends.iterator(); iter.hasNext();) 510 { 511 DatabaseBackend backend = (DatabaseBackend) iter.next(); 512 if (!backend.isValidBackendUser(vdbUser)) 513 { 514 result = false; 515 break; 516 } 517 } 518 return result; 519 } 520 521 528 protected ControllerResultSet statementExecuteQuery(SelectRequest request) 529 throws SQLException 530 { 531 if (request == null) 532 { 533 String msg = "Request failed (null read request received)"; 534 logger.warn(msg); 535 throw new SQLException (msg); 536 } 537 538 try 539 { 540 if (requestLogger.isInfoEnabled()) 541 requestLogger.info("S " + request.getId() + " " 542 + request.getTransactionId() + " " + request.getUniqueKey()); 543 544 request.setStartTime(System.currentTimeMillis()); 545 546 ControllerResultSet rs = requestManager.statementExecuteQuery(request); 547 548 request.setEndTime(System.currentTimeMillis()); 549 if (sqlMonitor != null && sqlMonitor.isActive()) 550 sqlMonitor.logRequestTime(request); 551 552 return rs; 553 } 554 catch (SQLException e) 555 { 556 String msg = "Request '" + request.getId() + "' failed (" 557 + e.getMessage() + ")"; 558 if (!request.isAutoCommit()) 559 { 560 msg = Translate.get("loadbalancer.request.failed.and.abort", 564 new String []{request.getSqlShortForm(getSqlShortFormLength()), 565 e.getMessage()}); 566 try 567 { 568 abort(request.getTransactionId(), true, false); 569 } 570 catch (SQLException e1) 571 { 572 if (logger.isInfoEnabled()) 573 logger 574 .info( 575 "Abort after request failure in transaction did not succeed probably because the transaction has already been aborted", 576 e); 577 } 578 } 579 logger.warn(msg); 580 if (sqlMonitor != null && sqlMonitor.isActive()) 581 sqlMonitor.logError(request); 582 throw e; 583 } 584 } 585 586 593 protected ExecuteUpdateResult statementExecuteUpdate( 594 AbstractWriteRequest request) throws SQLException 595 { 596 if (request == null) 597 { 598 String msg = "Request failed (null write request received)"; 599 logger.warn(msg); 600 throw new SQLException (msg); 601 } 602 603 try 604 { 605 if (requestLogger.isInfoEnabled()) 606 requestLogger.info("W " + request.getId() + " " 607 + request.getTransactionId() + " " + request.getUniqueKey()); 608 609 request.setStartTime(System.currentTimeMillis()); 610 611 ExecuteUpdateResult result = requestManager 612 .statementExecuteUpdate(request); 613 614 request.setEndTime(System.currentTimeMillis()); 615 if (sqlMonitor != null && sqlMonitor.isActive()) 616 sqlMonitor.logRequestTime(request); 617 618 return result; 619 } 620 catch (SQLException e) 621 { 622 String msg = "Request '" + request.getId() + "' failed (" 623 + e.getMessage() + ")"; 624 625 if (!request.isAutoCommit()) 626 { 627 msg = Translate.get("loadbalancer.request.failed.and.abort", 631 new String []{request.getSqlShortForm(getSqlShortFormLength()), 632 e.getMessage()}); 633 try 634 { 635 if (requestManager.getTransactionMetaData(new Long (request 636 .getTransactionId())) != null) 637 abort(request.getTransactionId(), true, false); 638 } 639 catch (SQLException e1) 640 { 641 if (logger.isInfoEnabled()) 642 logger 643 .info( 644 "Abort after request failure in transaction did not succeed probably because the transaction has already been aborted", 645 e); 646 } 647 } 648 649 logger.debug(msg); 651 if (sqlMonitor != null && sqlMonitor.isActive()) 652 sqlMonitor.logError(request); 653 throw e; 654 } 655 } 656 657 664 protected GeneratedKeysResult statementExecuteUpdateWithKeys( 665 AbstractWriteRequest request) throws SQLException 666 { 667 if (request == null) 668 { 669 String msg = "Request failed (null write request received)"; 670 logger.warn(msg); 671 throw new SQLException (msg); 672 } 673 674 try 675 { 676 if (requestLogger.isInfoEnabled()) 677 requestLogger.info("W " + request.getId() + " " 678 + request.getTransactionId() + " " + request.getUniqueKey()); 679 680 request.setStartTime(System.currentTimeMillis()); 681 682 GeneratedKeysResult result = requestManager 683 .statementExecuteUpdateWithKeys(request); 684 685 request.setEndTime(System.currentTimeMillis()); 686 if (sqlMonitor != null && sqlMonitor.isActive()) 687 sqlMonitor.logRequestTime(request); 688 689 return result; 690 } 691 catch (SQLException e) 692 { 693 String msg = "Request '" + request.getId() + "' failed (" 694 + e.getMessage() + ")"; 695 if (!request.isAutoCommit()) 696 { 697 abort(request.getTransactionId(), true, false); 701 msg = Translate.get("loadbalancer.request.failed.and.abort", 702 new String []{request.getSqlShortForm(getSqlShortFormLength()), 703 e.getMessage()}); 704 } 705 logger.warn(msg); 706 if (sqlMonitor != null && sqlMonitor.isActive()) 707 sqlMonitor.logError(request); 708 throw e; 709 } 710 } 711 712 720 protected ExecuteResult statementExecute(AbstractRequest request) 721 throws SQLException 722 { 723 if (request == null) 724 { 725 String msg = "Statement.execute() failed (null request received)"; 726 logger.warn(msg); 727 throw new SQLException (msg); 728 } 729 730 try 731 { 732 if (requestLogger.isInfoEnabled()) 733 requestLogger.info("E " + request.getId() + " " 734 + request.getTransactionId() + " " + request.getUniqueKey()); 735 736 request.setStartTime(System.currentTimeMillis()); 737 738 ExecuteResult result = requestManager.statementExecute(request); 739 740 request.setEndTime(System.currentTimeMillis()); 741 if (sqlMonitor != null && sqlMonitor.isActive()) 742 sqlMonitor.logRequestTime(request); 743 744 return result; 745 } 746 catch (AllBackendsFailedException e) 747 { 748 String msg = Translate.get( 749 "loadbalancer.storedprocedure.failed.on.all.backends", new String []{ 750 String.valueOf(request.getId()), e.getMessage()}); 751 if (!request.isAutoCommit()) 752 { 753 abort(request.getTransactionId(), true, false); 757 msg = Translate.get("loadbalancer.request.failed.and.abort", 758 new String []{request.getSqlShortForm(getSqlShortFormLength()), 759 e.getMessage()}); 760 } 761 logger.warn(msg); 762 if (sqlMonitor != null && sqlMonitor.isActive()) 763 sqlMonitor.logError(request); 764 throw new SQLException (msg); 765 } 766 catch (SQLException e) 767 { 768 String msg = Translate.get("loadbalancer.storedprocedure.failed", 769 new String []{String.valueOf(request.getId()), e.getMessage()}); 770 if (!request.isAutoCommit()) 771 { 772 abort(request.getTransactionId(), true, false); 776 msg = Translate.get("loadbalancer.request.failed.and.abort", 777 new String []{request.getSqlShortForm(getSqlShortFormLength()), 778 e.getMessage()}); 779 } 780 logger.warn(msg); 781 if (sqlMonitor != null && sqlMonitor.isActive()) 782 sqlMonitor.logError(request); 783 throw e; 784 } 785 } 786 787 794 protected ControllerResultSet callableStatementExecuteQuery( 795 StoredProcedure proc) throws SQLException 796 { 797 if (proc == null) 798 { 799 String msg = "Request failed (null stored procedure received)"; 800 logger.warn(msg); 801 throw new SQLException (msg); 802 } 803 804 try 805 { 806 if (requestLogger.isInfoEnabled()) 807 requestLogger.info("S " + proc.getId() + " " + proc.getTransactionId() 808 + " " + proc.getUniqueKey()); 809 810 proc.setStartTime(System.currentTimeMillis()); 811 812 ControllerResultSet rs = requestManager 813 .callableStatementExecuteQuery(proc); 814 815 proc.setEndTime(System.currentTimeMillis()); 816 if (sqlMonitor != null && sqlMonitor.isActive()) 817 sqlMonitor.logRequestTime(proc); 818 819 return rs; 820 } 821 catch (AllBackendsFailedException e) 822 { 823 String msg = Translate.get( 824 "loadbalancer.storedprocedure.failed.on.all.backends", new String []{ 825 String.valueOf(proc.getId()), e.getMessage()}); 826 if (!proc.isAutoCommit()) 827 { 828 abort(proc.getTransactionId(), true, false); 832 msg = Translate.get("loadbalancer.request.failed.and.abort", 833 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 834 e.getMessage()}); 835 } 836 logger.warn(msg); 837 if (sqlMonitor != null && sqlMonitor.isActive()) 838 sqlMonitor.logError(proc); 839 throw new SQLException (msg); 840 } 841 catch (SQLException e) 842 { 843 String msg = Translate.get("loadbalancer.storedprocedure.failed", 844 new String []{String.valueOf(proc.getId()), e.getMessage()}); 845 if (!proc.isAutoCommit()) 846 { 847 abort(proc.getTransactionId(), true, false); 851 msg = Translate.get("loadbalancer.request.failed.and.abort", 852 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 853 e.getMessage()}); 854 } 855 logger.warn(msg); 856 if (sqlMonitor != null && sqlMonitor.isActive()) 857 sqlMonitor.logError(proc); 858 throw e; 859 } 860 } 861 862 869 protected ExecuteUpdateResult callableStatementExecuteUpdate( 870 StoredProcedure proc) throws SQLException 871 { 872 if (proc == null) 873 { 874 String msg = "Request failed (null stored procedure received)"; 875 logger.warn(msg); 876 throw new SQLException (msg); 877 } 878 879 try 880 { 881 if (requestLogger.isInfoEnabled()) 882 requestLogger.info("W " + proc.getId() + " " + proc.getTransactionId() 883 + " " + proc.getUniqueKey()); 884 885 proc.setStartTime(System.currentTimeMillis()); 886 887 ExecuteUpdateResult result = requestManager 888 .callableStatementExecuteUpdate(proc); 889 890 proc.setEndTime(System.currentTimeMillis()); 891 if (sqlMonitor != null && sqlMonitor.isActive()) 892 sqlMonitor.logRequestTime(proc); 893 894 return result; 895 } 896 catch (AllBackendsFailedException e) 897 { 898 String msg = Translate.get( 899 "loadbalancer.storedprocedure.failed.on.all.backends", new String []{ 900 String.valueOf(proc.getId()), e.getMessage()}); 901 if (!proc.isAutoCommit()) 902 { 903 abort(proc.getTransactionId(), true, false); 907 msg = Translate.get("loadbalancer.request.failed.and.abort", 908 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 909 e.getMessage()}); 910 } 911 logger.warn(msg); 912 if (sqlMonitor != null && sqlMonitor.isActive()) 913 sqlMonitor.logError(proc); 914 throw new SQLException (msg); 915 } 916 catch (SQLException e) 917 { 918 String msg = Translate.get("loadbalancer.storedprocedure.failed", 919 new String []{String.valueOf(proc.getId()), e.getMessage()}); 920 if (!proc.isAutoCommit()) 921 { 922 abort(proc.getTransactionId(), true, false); 926 msg = Translate.get("loadbalancer.request.failed.and.abort", 927 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 928 e.getMessage()}); 929 } 930 logger.warn(msg); 931 if (sqlMonitor != null && sqlMonitor.isActive()) 932 sqlMonitor.logError(proc); 933 throw e; 934 } 935 } 936 937 945 protected ExecuteResult callableStatementExecute(StoredProcedure proc) 946 throws SQLException 947 { 948 if (proc == null) 949 { 950 String msg = "Request failed (null stored procedure received)"; 951 logger.warn(msg); 952 throw new SQLException (msg); 953 } 954 955 try 956 { 957 if (requestLogger.isInfoEnabled()) 958 requestLogger.info("E " + proc.getId() + " " + proc.getTransactionId() 959 + " " + proc.getUniqueKey()); 960 961 proc.setStartTime(System.currentTimeMillis()); 962 963 ExecuteResult result = requestManager.callableStatementExecute(proc); 964 965 proc.setEndTime(System.currentTimeMillis()); 966 if (sqlMonitor != null && sqlMonitor.isActive()) 967 sqlMonitor.logRequestTime(proc); 968 969 return result; 970 } 971 catch (AllBackendsFailedException e) 972 { 973 String msg = Translate.get( 974 "loadbalancer.storedprocedure.failed.on.all.backends", new String []{ 975 String.valueOf(proc.getId()), e.getMessage()}); 976 if (!proc.isAutoCommit()) 977 { 978 abort(proc.getTransactionId(), true, false); 982 msg = Translate.get("loadbalancer.request.failed.and.abort", 983 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 984 e.getMessage()}); 985 } 986 logger.warn(msg); 987 if (sqlMonitor != null && sqlMonitor.isActive()) 988 sqlMonitor.logError(proc); 989 throw new SQLException (msg); 990 } 991 catch (SQLException e) 992 { 993 String msg = Translate.get("loadbalancer.storedprocedure.failed", 994 new String []{String.valueOf(proc.getId()), e.getMessage()}); 995 if (!proc.isAutoCommit()) 996 { 997 abort(proc.getTransactionId(), true, false); 1001 msg = Translate.get("loadbalancer.request.failed.and.abort", 1002 new String []{proc.getSqlShortForm(getSqlShortFormLength()), 1003 e.getMessage()}); 1004 } 1005 logger.warn(msg); 1006 if (sqlMonitor != null && sqlMonitor.isActive()) 1007 sqlMonitor.logError(proc); 1008 throw e; 1009 } 1010 } 1011 1012 1018 public void closePersistentConnection(String login, 1019 long persistentConnectionId) 1020 { 1021 requestManager.closePersistentConnection(login, persistentConnectionId); 1022 } 1023 1024 1031 public boolean hasPersistentConnection(long persistentConnectionId) 1032 { 1033 return requestManager.hasPersistentConnection(persistentConnectionId); 1034 } 1035 1036 1043 public void openPersistentConnection(String login, long persistentConnectionId) 1044 throws SQLException 1045 { 1046 requestManager.openPersistentConnection(login, persistentConnectionId); 1047 } 1048 1049 1055 public void failoverForTransaction(long currentTid) 1056 { 1057 logger.info("Transparent client failover operated for transaction " 1058 + currentTid); 1059 } 1060 1061 1067 public void failoverForPersistentConnection(long persistentConnectionId) 1068 { 1069 logger 1072 .info("Unexpected transparent client failover operated for persistent connection " 1073 + persistentConnectionId); 1074 } 1075 1076 private static final Object CONNECTION_ID_SYNC_OBJECT = new Object (); 1077 1078 1083 public long getNextConnectionId() 1084 { 1085 synchronized (CONNECTION_ID_SYNC_OBJECT) 1086 { 1087 return connectionId++; 1088 } 1089 } 1090 1091 1096 public long getNextRequestId() 1097 { 1098 return requestManager.getNextRequestId(); 1099 } 1100 1101 1109 public ControllerResultSet getPreparedStatementGetMetaData( 1110 AbstractRequest request) throws SQLException 1111 { 1112 try 1113 { 1114 return requestManager.getPreparedStatementGetMetaData(request); 1115 } 1116 catch (NoMoreBackendException e) 1117 { 1118 throw e; 1119 } 1120 } 1121 1122 1125 1126 1144 public long begin(String login, boolean isPersistentConnection, 1145 long persistentConnectionId) throws SQLException 1146 { 1147 try 1148 { 1149 long tid = requestManager.begin(login, isPersistentConnection, 1150 persistentConnectionId); 1151 if (requestLogger.isInfoEnabled()) 1152 requestLogger.info("B " + tid); 1153 return tid; 1154 } 1155 catch (SQLException e) 1156 { 1157 String msg = "Begin failed (" + e.getMessage() + ")"; 1158 logger.warn(msg); 1159 throw e; 1160 } 1161 } 1162 1163 1183 public void abort(long transactionId, boolean logAbort, boolean forceAbort) 1184 throws SQLException 1185 { 1186 requestManager.abort(transactionId, logAbort, forceAbort); 1187 if (requestLogger.isInfoEnabled()) 1189 requestLogger.info("R " + transactionId); 1190 } 1191 1192 1201 public void commit(long transactionId, boolean logCommit, 1202 boolean emptyTransaction) throws SQLException 1203 { 1204 try 1205 { 1206 if (requestLogger.isInfoEnabled()) 1207 requestLogger.info("C " + transactionId); 1208 requestManager.commit(transactionId, logCommit, emptyTransaction); 1209 } 1210 catch (SQLException e) 1211 { 1212 1213 String msg = "Commit of transaction '" + transactionId + "' failed (" 1214 + e.getMessage() + ")"; 1215 1216 msg = Translate.get("loadbalancer.commit.failed.and.abort", new String []{ 1220 Long.toString(transactionId), e.getMessage()}); 1221 try 1222 { 1223 abort(transactionId, true, false); 1224 } 1225 catch (SQLException e1) 1226 { 1227 if (logger.isInfoEnabled()) 1228 logger 1229 .info( 1230 "Abort after commit failure in transaction did not succeed probably because the transaction has already been aborted", 1231 e); 1232 } 1233 1234 logger.warn(msg); 1235 throw e; 1236 } 1237 } 1238 1239 1247 public void rollback(long transactionId, boolean logRollback) 1248 throws SQLException 1249 { 1250 try 1251 { 1252 if (requestLogger.isInfoEnabled()) 1253 requestLogger.info("R " + transactionId); 1254 requestManager.rollback(transactionId, logRollback); 1255 } 1256 catch (SQLException e) 1257 { 1258 String msg = "Rollback of transaction '" + transactionId + "' failed (" 1259 + e.getMessage() + ")"; 1260 logger.warn(msg); 1261 throw e; 1262 } 1263 } 1264 1265 1272 public void rollback(long transactionId, String savepointName) 1273 throws SQLException 1274 { 1275 try 1276 { 1277 if (requestLogger.isInfoEnabled()) 1278 requestLogger.info("R " + transactionId + " " + savepointName); 1279 requestManager.rollback(transactionId, savepointName); 1280 } 1281 catch (SQLException e) 1282 { 1283 String msg = "Rollback to savepoint '" + savepointName + "' for " 1284 + "transaction '" + transactionId + "' failed (" + e.getMessage() 1285 + ")"; 1286 logger.warn(msg); 1287 throw e; 1288 } 1289 } 1290 1291 1298 public int setSavepoint(long transactionId) throws SQLException 1299 { 1300 try 1301 { 1302 int savepointId = requestManager.setSavepoint(transactionId); 1303 if (requestLogger.isInfoEnabled()) 1304 requestLogger.info("P " + transactionId + " " + savepointId); 1305 return savepointId; 1306 } 1307 catch (SQLException e) 1308 { 1309 String msg = "Setting unnamed savepoint to transaction '" + transactionId 1310 + "' failed (" + e.getMessage() + ")"; 1311 logger.warn(msg); 1312 throw e; 1313 } 1314 } 1315 1316 1323 public void setSavepoint(long transactionId, String name) throws SQLException 1324 { 1325 try 1326 { 1327 if (requestLogger.isInfoEnabled()) 1328 requestLogger.info("P " + transactionId + " " + name); 1329 requestManager.setSavepoint(transactionId, name); 1330 } 1331 catch (SQLException e) 1332 { 1333 String msg = "Setting savepoint with name '" + name + "' to transaction " 1334 + "'" + transactionId + "' failed (" + e.getMessage() + ")"; 1335 logger.warn(msg); 1336 throw e; 1337 } 1338 } 1339 1340 1347 public void releaseSavepoint(long transactionId, String savepointName) 1348 throws SQLException 1349 { 1350 try 1351 { 1352 if (requestLogger.isInfoEnabled()) 1353 requestLogger.info("F " + transactionId + " " + savepointName); 1354 requestManager.releaseSavepoint(transactionId, savepointName); 1355 } 1356 catch (SQLException e) 1357 { 1358 String msg = "Releasing savepoint with name '" + savepointName 1359 + "' from " + "transaction '" + transactionId + "' failed (" 1360 + e.getMessage() + ")"; 1361 logger.warn(msg); 1362 throw e; 1363 } 1364 } 1365 1366 1370 1376 public void addBackend(DatabaseBackend db) throws VirtualDatabaseException 1377 { 1378 this.addBackend(db, true); 1379 } 1380 1381 1388 public void addBackend(DatabaseBackend db, boolean checkForCompliance) 1389 throws VirtualDatabaseException 1390 { 1391 if (db == null) 1392 { 1393 String msg = "Illegal null database backend in addBackend(DatabaseBackend) method"; 1394 logger.error(msg); 1395 throw new VirtualDatabaseException(msg); 1396 } 1397 1398 if (db.isReadEnabled()) 1399 { 1400 String msg = "It is not allowed to add an enabled database."; 1401 logger.error(msg); 1402 throw new VirtualDatabaseException(msg); 1403 } 1404 1405 try 1407 { 1408 rwLock.acquireWrite(); 1409 } 1410 catch (InterruptedException e) 1411 { 1412 String msg = Translate.get( 1413 "loadbalancer.backendlist.acquire.writelock.failed", e); 1414 logger.error(msg); 1415 throw new VirtualDatabaseException(msg); 1416 } 1417 1418 if (backends.indexOf(db) != -1) 1420 { 1421 rwLock.releaseWrite(); 1422 String msg = "Duplicate backend " + db.getURL(); 1423 logger.warn(msg); 1424 throw new VirtualDatabaseException(msg); 1425 } 1426 1427 ArrayList logins = authenticationManager.getVirtualLogins(); 1429 VirtualDatabaseUser vdu; 1430 String login; 1431 for (int i = 0; i < logins.size(); i++) 1432 { 1433 vdu = (VirtualDatabaseUser) logins.get(i); 1434 login = vdu.getLogin(); 1435 if (db.getConnectionManager(login) == null) 1436 { 1437 rwLock.releaseWrite(); 1438 throw new VirtualDatabaseException(Translate.get( 1439 "backend.missing.connection.manager", login)); 1440 } 1441 } 1442 1443 try 1445 { 1446 if (logger.isDebugEnabled()) 1447 logger.debug("Checking driver compliance"); 1448 if (checkForCompliance) 1449 db.checkDriverCompliance(); } 1451 catch (Exception e) 1452 { 1453 rwLock.releaseWrite(); 1454 String msg = "Error while adding database backend " + db.getName() + " (" 1455 + e + ")"; 1456 logger.warn(msg); 1457 throw new VirtualDatabaseException(msg); 1458 } 1459 1460 db.setSqlShortFormLength(getSqlShortFormLength()); 1461 1462 backends.add(db); 1464 if (logger.isDebugEnabled()) 1465 logger.debug("Backend " + db.getName() + " added successfully"); 1466 1467 1477 if (getRequestManager() != null) 1478 { 1479 db.setStateListener(getRequestManager().getBackendStateListener()); 1480 } 1481 1482 rwLock.releaseWrite(); 1484 1485 sendJmxNotification(SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ADDED, 1487 Translate.get("notification.backend.added", db.getName())); 1488 1489 try 1491 { 1492 ObjectName objectName = JmxConstants.getDatabaseBackendObjectName(name, 1493 db.getName()); 1494 org.continuent.sequoia.controller.backend.management.DatabaseBackend managingBackend = new org.continuent.sequoia.controller.backend.management.DatabaseBackend( 1495 db); 1496 db.setNotificationBroadcaster(managingBackend.getBroadcaster()); 1497 MBeanServerManager.registerMBean(managingBackend, objectName); 1498 } 1499 catch (Exception e) 1500 { 1501 logger.error(Translate.get("virtualdatabase.fail.register.backend.mbean", 1502 db.getName()), e); 1503 } 1504 } 1505 1506 1509 public void forceDisableBackend(String backendName) 1510 throws VirtualDatabaseException 1511 { 1512 try 1513 { 1514 DatabaseBackend db = getAndCheckBackend(backendName, 1515 CHECK_BACKEND_DISABLE); 1516 requestManager.disableBackend(db, true); 1517 requestManager 1518 .setDatabaseSchema(getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames()); 1519 1520 sendJmxNotification( 1521 SequoiaNotificationList.VIRTUALDATABASE_BACKEND_DISABLED, Translate 1522 .get("notification.backend.disabled", db.getName())); 1523 } 1524 catch (Exception e) 1525 { 1526 logger.error("An error occured while disabling backend " + backendName 1527 + " (" + e + ")"); 1528 throw new VirtualDatabaseException(e.getMessage(), e); 1529 } 1530 } 1531 1532 1542 public void disableAllBackends(boolean forceEnable) 1543 throws VirtualDatabaseException 1544 { 1545 try 1546 { 1547 int size = this.backends.size(); 1548 DatabaseBackend dbe; 1549 for (int i = 0; i < size; i++) 1550 { 1551 dbe = (DatabaseBackend) backends.get(i); 1552 if (dbe.isReadEnabled()) 1553 requestManager.disableBackend(getAndCheckBackend(dbe.getName(), 1554 CHECK_BACKEND_DISABLE), forceEnable); 1555 } 1556 } 1557 catch (Exception e) 1558 { 1559 throw new VirtualDatabaseException(e.getMessage(), e); 1560 } 1561 } 1562 1563 1566 public void disableBackendWithCheckpoint(String backendName) 1567 throws VirtualDatabaseException 1568 { 1569 try 1570 { 1571 DatabaseBackend backend = getAndCheckBackend(backendName, 1572 NO_CHECK_BACKEND); 1573 if (backend.isDisabled()) 1574 { 1575 logger.info("Backend " + backendName + " is already disabled."); 1576 return; 1578 } 1579 requestManager.disableBackendWithCheckpoint(backend, 1580 buildCheckpointName("disable " + backendName)); 1581 if (requestManager.getLoadBalancer().getRAIDbLevel() != RAIDbLevels.RAIDb1) 1583 requestManager 1584 .setDatabaseSchema(getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames()); 1585 } 1586 catch (Exception e) 1587 { 1588 logger.error("An error occured while disabling backend " + backendName 1589 + " (" + e + ")"); 1590 throw new VirtualDatabaseException(e.getMessage(), e); 1591 } 1592 } 1593 1594 1600 public void disableAllBackendsWithCheckpoint(String checkpoint) 1601 throws VirtualDatabaseException 1602 { 1603 if (checkpoint == null) 1604 { 1605 disableAllBackends(false); 1606 return; 1607 } 1608 1609 try 1610 { 1611 this.acquireReadLockBackendLists(); 1612 } 1613 catch (InterruptedException e) 1614 { 1615 throw new VirtualDatabaseException(e.getMessage(), e); 1616 } 1617 1618 try 1619 { 1620 ArrayList backendInfos = new ArrayList (); 1621 Iterator iter = backends.iterator(); 1622 while (iter.hasNext()) 1623 { 1624 DatabaseBackend backend = (DatabaseBackend) iter.next(); 1625 backendInfos.add(new BackendInfo(backend)); 1626 } 1627 requestManager.disableBackendsWithCheckpoint(backendInfos, checkpoint); 1628 } 1629 catch (Exception e) 1630 { 1631 throw new VirtualDatabaseException(e.getMessage(), e); 1632 } 1633 finally 1634 { 1635 this.releaseReadLockBackendLists(); 1636 } 1637 } 1638 1639 1646 private void enableBackendSanityChecks() throws VirtualDatabaseException 1647 { 1648 if (isResyncing()) 1649 { 1650 String msg = Translate.get("virtualdatabase.fail.enable.cause.resyncing"); 1651 logger.warn(msg); 1652 throw new VirtualDatabaseException(msg); 1653 } 1654 1655 if (isShuttingDown()) 1656 { 1657 String msg = Translate.get("virtualdatabase.fail.enable.cause.shutdown "); 1658 logger.warn(msg); 1659 throw new VirtualDatabaseException(msg); 1660 } 1661 } 1662 1663 1671 public void enableBackendFromCheckpoint(String backendName, 1672 String checkpointName) throws VirtualDatabaseException 1673 { 1674 enableBackendSanityChecks(); 1675 1676 EnableBackendOperation enableOperation = new EnableBackendOperation( 1677 backendName); 1678 addAdminOperation(enableOperation); 1679 1680 try 1682 { 1683 DatabaseBackend backend = getAndCheckBackend(backendName, 1684 CHECK_BACKEND_ENABLE); 1685 RecoverThread recoverThread = requestManager.enableBackendFromCheckpoint( 1686 backend, checkpointName); 1687 recoverThread.join(); 1689 if (recoverThread.getException() != null) 1690 { 1691 throw recoverThread.getException(); 1692 } 1693 requestManager.setSchemaIsDirty(true); 1694 1695 getStaticMetaData().gatherStaticMetadata(backend); 1697 1698 if (databaseProductNames.indexOf(backend.getDatabaseProductName()) == -1) 1700 databaseProductNames += "," + backend.getDatabaseProductName(); 1701 } 1702 catch (Exception e) 1703 { 1704 String msg = Translate.get( 1705 "virtualdatabase.enable.from.checkpoint.failed", new Object []{name, 1706 backendName, e}); 1707 logger.warn(msg, e); 1708 throw new VirtualDatabaseException(msg, e); 1709 } 1710 finally 1711 { 1712 removeAdminOperation(enableOperation); 1713 } 1714 } 1715 1716 1719 public void enableBackendFromCheckpoint(String backendName) 1720 throws VirtualDatabaseException 1721 { 1722 enableBackendSanityChecks(); 1723 1724 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND); 1725 String checkpoint = backend.getLastKnownCheckpoint(); 1726 if ((checkpoint == null) || ("".equals(checkpoint))) 1727 throw new VirtualDatabaseException( 1728 "Cannot enable backend " 1729 + backendName 1730 + " from a known state. Resynchronize this backend by restoring a dump."); 1731 else 1732 { 1733 if (logger.isDebugEnabled()) 1734 logger.debug("Enabling backend " + backendName 1735 + " from its last checkpoint " + backend.getLastKnownCheckpoint()); 1736 } 1737 enableBackendFromCheckpoint(backendName, backend.getLastKnownCheckpoint()); 1738 } 1739 1740 1745 public void enableAllBackends() throws VirtualDatabaseException 1746 { 1747 enableBackendSanityChecks(); 1748 1749 try 1750 { 1751 int size = this.backends.size(); 1752 DatabaseBackend dbe; 1753 for (int i = 0; i < size; i++) 1754 { 1755 dbe = (DatabaseBackend) backends.get(i); 1756 if (!dbe.isReadEnabled()) 1757 forceEnableBackend(((DatabaseBackend) backends.get(i)).getName()); 1758 } 1759 } 1760 catch (RuntimeException e) 1761 { 1762 logger.error("Runtime error in enableAllBackends", e); 1763 throw new VirtualDatabaseException(e.getMessage(), e); 1764 } 1765 } 1766 1767 1778 public void enableAllBackendsFromCheckpoint() throws VirtualDatabaseException 1779 { 1780 RecoveryLog log = requestManager.getRecoveryLog(); 1781 if (log == null) 1782 { logger 1784 .warn("No recovery log has been configured, enabling backend without checkpoint."); 1785 enableAllBackends(); 1786 } 1787 else 1788 { 1789 enableBackendSanityChecks(); 1790 1791 try 1792 { 1793 int size = this.backends.size(); 1794 DatabaseBackend dbe; 1795 String backendName; 1796 BackendRecoveryInfo info; 1797 for (int i = 0; i < size; i++) 1798 { 1799 dbe = (DatabaseBackend) backends.get(i); 1800 backendName = dbe.getName(); 1801 info = log.getBackendRecoveryInfo(name, backendName); 1802 switch (info.getBackendState()) 1803 { 1804 case BackendState.DISABLED : 1805 String checkpoint = info.getCheckpoint(); 1806 if (checkpoint == null || checkpoint.equals("")) 1807 { 1808 logger 1809 .warn("Cannot enable backend " 1810 + backendName 1811 + " from a known state. Resynchronize this backend by restoring a dump."); 1812 } 1813 else 1814 { 1815 logger.info("Enabling backend " + backendName 1816 + " from checkpoint " + checkpoint); 1817 enableBackendFromCheckpoint(dbe.getName(), checkpoint); 1818 } 1819 continue; 1820 case BackendState.UNKNOWN : 1821 logger.info("Unknown last state for backend " + backendName 1822 + ". Leaving node in " 1823 + (dbe.isReadEnabled() ? "enabled" : "disabled") + " state."); 1824 continue; 1825 case BackendState.BACKUPING : 1826 case BackendState.DISABLING : 1827 case BackendState.RESTORING : 1828 case BackendState.REPLAYING : 1829 if (!dbe.isReadEnabled()) 1830 { 1831 logger.info("Unexpected transition state (" 1832 + info.getBackendState() + ") for backend " + backendName 1833 + ". Forcing backend to disabled state."); 1834 info.setBackendState(BackendState.DISABLED); 1835 log.storeBackendRecoveryInfo(name, info); 1836 } 1837 else 1838 logger.info("Unexpected transition state (" 1839 + info.getBackendState() + ") for backend " + backendName 1840 + ". Leaving backend in its current state."); 1841 continue; 1842 default : 1843 if (!dbe.isReadEnabled()) 1844 { 1845 logger.info("Unexpected enabled state (" 1846 + info.getBackendState() + ") for backend " + backendName 1847 + ". Forcing backend to disabled state."); 1848 info.setBackendState(BackendState.DISABLED); 1849 log.storeBackendRecoveryInfo(name, info); 1850 } 1851 else 1852 logger.info("Unexpected enabled state (" 1853 + info.getBackendState() + ") for backend " + backendName 1854 + ". Leaving backend in its current state."); 1855 continue; 1856 } 1857 } 1858 } 1859 catch (Exception e) 1860 { 1861 throw new VirtualDatabaseException(e.getMessage(), e); 1862 } 1863 } 1864 } 1865 1866 1869 public void forceEnableBackend(String backendName) 1870 throws VirtualDatabaseException 1871 { 1872 enableBackendSanityChecks(); 1873 1874 EnableBackendOperation enableOperation = new EnableBackendOperation( 1875 backendName + " (force)"); 1876 addAdminOperation(enableOperation); 1877 1878 try 1880 { 1881 DatabaseBackend backend = getAndCheckBackend(backendName, 1882 CHECK_BACKEND_ENABLE); 1883 1884 requestManager.enableBackend(backend); 1885 requestManager.setSchemaIsDirty(true); 1886 1887 if (databaseProductNames.indexOf(backend.getDatabaseProductName()) == -1) 1889 databaseProductNames += "," + backend.getDatabaseProductName(); 1890 1891 getStaticMetaData().gatherStaticMetadata(backend); 1893 1894 sendJmxNotification( 1895 SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ENABLED, Translate 1896 .get("notification.backend.enabled")); 1897 } 1898 catch (Exception e) 1899 { 1900 throw new VirtualDatabaseException(e.getMessage(), e); 1901 } 1902 finally 1903 { 1904 removeAdminOperation(enableOperation); 1905 } 1906 } 1907 1908 1917 public void forceEnableAllBackendsFromCheckpoint(String checkpoint) 1918 throws VirtualDatabaseException 1919 { 1920 enableBackendSanityChecks(); 1921 1922 if (checkpoint == null || checkpoint.equals("")) 1923 enableAllBackends(); 1924 else 1925 { 1926 try 1927 { 1928 int size = this.backends.size(); 1929 DatabaseBackend backend; 1930 for (int i = 0; i < size; i++) 1931 { 1932 backend = (DatabaseBackend) backends.get(i); 1933 if (!backend.isReadEnabled()) 1934 { 1935 backend.setLastKnownCheckpoint(checkpoint); 1936 enableBackendFromCheckpoint(backend.getName(), checkpoint); 1937 } 1938 } 1939 } 1940 catch (RuntimeException e) 1941 { 1942 logger 1943 .error("Runtime error in forceEnableAllBackendsFromCheckpoint", e); 1944 throw new VirtualDatabaseException(e.getMessage(), e); 1945 } 1946 } 1947 } 1948 1949 1952 public ArrayList getAllBackendNames() throws VirtualDatabaseException 1953 { 1954 try 1955 { 1956 acquireReadLockBackendLists(); 1957 } 1958 catch (InterruptedException e) 1959 { 1960 String msg = "Unable to acquire read lock on backend list in getAllBackendNames (" 1961 + e + ")"; 1962 logger.error(msg); 1963 throw new VirtualDatabaseException(msg); 1964 } 1965 1966 int size = backends.size(); 1967 ArrayList result = new ArrayList (); 1968 for (int i = 0; i < size; i++) 1969 { 1970 result.add(((DatabaseBackend) backends.get(i)).getName()); 1971 } 1972 1973 releaseReadLockBackendLists(); 1974 return result; 1975 } 1976 1977 1990 public DatabaseBackend getAndCheckBackend(String backendName, int testEnable) 1991 throws VirtualDatabaseException 1992 { 1993 try 1994 { 1995 acquireReadLockBackendLists(); 1996 } 1997 catch (InterruptedException e) 1998 { 1999 String msg = "Unable to acquire read lock on backend list in getAndCheckBackend (" 2000 + e + ")"; 2001 logger.error(msg); 2002 throw new VirtualDatabaseException(msg); 2003 } 2004 2005 DatabaseBackend b; 2006 try 2007 { 2008 int size = backends.size(); 2010 b = null; 2011 for (int i = 0; i < size; i++) 2012 { 2013 b = (DatabaseBackend) backends.get(i); 2014 if (b.getName().equals(backendName)) 2015 break; 2016 else 2017 b = null; 2018 } 2019 2020 if (b == null) 2022 { 2023 String msg = "Trying to access a non-existing backend " + backendName; 2024 logger.warn(msg); 2025 throw new VirtualDatabaseException(msg); 2026 } 2027 2028 switch (testEnable) 2030 { 2031 case NO_CHECK_BACKEND : 2032 break; 2033 case CHECK_BACKEND_DISABLE : 2034 if (!b.isReadEnabled()) 2035 { 2036 String msg = "Backend " + backendName + " is already disabled"; 2037 logger.warn(msg); 2038 throw new VirtualDatabaseException(msg); 2039 } 2040 break; 2041 case CHECK_BACKEND_ENABLE : 2042 if (b.isReadEnabled()) 2043 { 2044 String msg = "Backend " + backendName + " is already enabled"; 2045 logger.warn(msg); 2046 throw new VirtualDatabaseException(msg); 2047 } 2048 break; 2049 default : 2050 String msg = "Unexpected parameter in getAndCheckBackend(...)"; 2051 logger.error(msg); 2052 throw new VirtualDatabaseException(msg); 2053 } 2054 } 2055 finally 2056 { 2057 releaseReadLockBackendLists(); 2058 } 2059 2060 if (testEnable == CHECK_BACKEND_ENABLE) 2061 { 2062 try 2064 { 2065 if (logger.isDebugEnabled()) 2066 logger.debug("Initializing connections for backend " + b.getName()); 2067 b.initializeConnections(); 2068 2069 b.checkDriverCompliance(); 2070 2071 if (logger.isDebugEnabled()) 2072 logger.debug("Checking schema for backend " + b.getName()); 2073 b.checkDatabaseSchema(null); 2074 2075 DatabaseSchema backendSchema = b.getDatabaseSchema(); 2076 2077 if (backendSchema != null) 2078 requestManager.mergeDatabaseSchema(backendSchema); 2079 else 2080 logger.warn("Backend " + b.getName() + " has no defined schema."); 2081 } 2082 catch (SQLException e) 2083 { 2084 String msg = "Error while initalizing database backend " + b.getName() 2085 + " (" + e + ")"; 2086 logger.warn(msg, e); 2087 throw new VirtualDatabaseException(msg, e); 2088 } 2089 } 2090 2091 return b; 2092 } 2093 2094 2100 protected boolean isResyncing() 2101 { 2102 return false; 2103 } 2104 2105 2109 public void replicateBackend(String backendName, String newBackendName, 2110 Map parameters) throws VirtualDatabaseException 2111 { 2112 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND); 2114 DatabaseBackend newBackend = null; 2115 2116 try 2118 { 2119 newBackend = backend.copy(newBackendName, parameters); 2120 } 2121 catch (Exception e) 2122 { 2123 String msg = Translate.get("virtualdatabase.fail.backend.copy", e); 2124 logger.warn(msg, e); 2125 throw new VirtualDatabaseException(msg, e); 2126 } 2127 2128 addBackend(newBackend); 2130 } 2131 2132 2139 public void removeBackend(String backend) throws VirtualDatabaseException 2140 { 2141 removeBackend(getAndCheckBackend(backend, NO_CHECK_BACKEND)); 2142 } 2143 2144 2150 public void removeBackend(DatabaseBackend db) throws VirtualDatabaseException 2151 { 2152 if (db == null) 2153 { 2154 String msg = "Illegal null database backend in removeBackend(DatabaseBackend) method"; 2155 logger.error(msg); 2156 throw new VirtualDatabaseException(msg); 2157 } 2158 2159 try 2160 { 2161 rwLock.acquireWrite(); 2162 } 2163 catch (InterruptedException e) 2164 { 2165 String msg = Translate.get( 2166 "loadbalancer.backendlist.acquire.writelock.failed", e); 2167 logger.error(msg); 2168 throw new VirtualDatabaseException(msg); 2169 } 2170 2171 int idx = backends.indexOf(db); 2173 if (idx == -1) 2174 { 2175 rwLock.releaseWrite(); String msg = "Trying to remove a non-existing backend " + db.getName(); 2177 logger.warn(msg); 2178 throw new VirtualDatabaseException(msg); 2179 } 2180 2181 if (((DatabaseBackend) backends.get(idx)).isReadEnabled()) 2182 { 2183 rwLock.releaseWrite(); String msg = "Trying to remove an enabled backend " + db.getName(); 2185 logger.error(msg); 2186 throw new VirtualDatabaseException(msg); 2187 } 2188 2189 backends.remove(idx); 2191 rwLock.releaseWrite(); 2193 sendJmxNotification( 2194 SequoiaNotificationList.VIRTUALDATABASE_BACKEND_REMOVED, Translate 2195 .get("notification.backend.removed")); 2196 2197 try 2199 { 2200 ObjectName objectName = JmxConstants.getDatabaseBackendObjectName(name, 2201 db.getName()); 2202 MBeanServerManager.unregister(objectName); 2203 } 2204 catch (Exception e) 2205 { 2206 logger.error(Translate.get( 2207 "virtualdatabase.fail.unregister.backend.mbean", db.getName()), e); 2208 } 2209 2210 if (logger.isDebugEnabled()) 2211 logger.debug("Backend " + db.getName() + " removed successfully"); 2212 } 2213 2214 2218 public void transferBackend(String backend, String controllerDestination) 2219 throws VirtualDatabaseException 2220 { 2221 throw new VirtualDatabaseException("Cannot transfer backend to controller:" 2222 + controllerDestination + " because database is not distributed"); 2223 } 2224 2225 2229 2237 public String buildCheckpointName(String event) 2238 { 2239 2242 SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyyMMddHHmmssSSSZ"); 2243 return (event + "-" + controller.getControllerName() + "-" + dateFormat 2244 .format(new Date (System.currentTimeMillis()))); 2245 } 2246 2247 2251 public void backupBackend(String backendName, String login, String password, 2252 String dumpName, String backuperName, String path, boolean force, 2253 ArrayList tables) throws VirtualDatabaseException 2254 { 2255 if (!isDumpNameAvailable(dumpName)) 2257 { 2258 throw new VirtualDatabaseException(Translate.get( 2259 "virtualdatabase.backup.dumpNameError", dumpName)); 2260 } 2261 if (!force && (getNumberOfEnabledBackends() == 1)) 2262 { 2263 throw new VirtualDatabaseException(Translate 2264 .get("virtualdatabase.backup.onlyOneBackendLeft")); 2265 } 2266 2267 BackupBackendOperation backupOperation = new BackupBackendOperation( 2269 backendName, dumpName); 2270 try 2271 { 2272 addAdminOperation(backupOperation); 2273 DatabaseBackend db = getAndCheckBackend(backendName, NO_CHECK_BACKEND); 2274 requestManager.backupBackend(db, login, password, dumpName, backuperName, 2275 path, tables); 2276 } 2277 catch (SQLException sql) 2278 { 2279 throw new VirtualDatabaseException(sql); 2280 } 2281 finally 2282 { 2283 removeAdminOperation(backupOperation); 2284 } 2285 } 2286 2287 protected int getNumberOfEnabledBackends() throws VirtualDatabaseException 2288 { 2289 if (true) 2291 return -1; 2292 2293 try 2294 { 2295 acquireReadLockBackendLists(); 2296 } 2297 catch (InterruptedException e) 2298 { 2299 String msg = Translate.get("virtualdatabase.fail.read.lock"); 2300 logger.error(msg, e); 2301 throw new VirtualDatabaseException(msg, e); 2302 } 2303 2304 int nbActive = 0; 2305 DatabaseBackend b; 2306 int size = backends.size(); 2307 b = null; 2308 for (int i = 0; i < size; i++) 2309 { 2310 b = (DatabaseBackend) backends.get(i); 2311 if (b.isReadEnabled() || b.isWriteEnabled()) 2312 nbActive++; 2314 } 2315 2316 releaseReadLockBackendLists(); 2317 2318 return nbActive; 2319 } 2320 2321 2330 public boolean isDumpNameAvailable(String tentativeDumpName) 2331 { 2332 DumpInfo[] dumps; 2333 try 2334 { 2335 dumps = getAvailableDumps(); 2336 } 2337 catch (VirtualDatabaseException e) 2338 { 2339 return true; 2340 } 2341 for (int i = 0; i < dumps.length; i++) 2342 { 2343 DumpInfo dump = dumps[i]; 2344 if (dump.getDumpName().equals(tentativeDumpName)) 2345 { 2346 return false; 2347 } 2348 } 2349 return true; 2350 } 2351 2352 2356 public void copyLogFromCheckpoint(String dumpName, String controllerName) 2357 throws VirtualDatabaseException 2358 { 2359 if (!hasRecoveryLog()) 2360 throw new VirtualDatabaseException(Translate 2361 .get("virtualdatabase.no.recovery.log")); 2362 if (!isDistributed()) 2363 throw new VirtualDatabaseException(Translate 2364 .get("virtualdatabase.not.distributed")); 2365 2366 2372 } 2373 2374 2377 public void deleteLogUpToCheckpoint(String checkpointName) 2378 throws VirtualDatabaseException 2379 { 2380 if (!hasRecoveryLog()) 2381 throw new VirtualDatabaseException(Translate 2382 .get("virtualdatabase.no.recovery.log")); 2383 2384 try 2385 { 2386 getRequestManager().getRecoveryLog().deleteLogEntriesBeforeCheckpoint( 2387 checkpointName); 2388 } 2389 catch (SQLException e) 2390 { 2391 throw new VirtualDatabaseException(e); 2392 } 2393 } 2394 2395 2398 public String [] getBackuperNames() 2399 { 2400 return requestManager.getBackupManager().getBackuperNames(); 2401 } 2402 2403 2406 public DumpInfo[] getAvailableDumps() throws VirtualDatabaseException 2407 { 2408 try 2409 { 2410 RecoveryLog recoveryLog = requestManager.getRecoveryLog(); 2411 if (recoveryLog == null) 2412 { 2413 return new DumpInfo[0]; 2414 } 2415 else 2416 { 2417 ArrayList dumps = recoveryLog.getDumpList(); 2418 return (DumpInfo[]) dumps.toArray(new DumpInfo[dumps.size()]); 2419 } 2420 } 2421 catch (SQLException e) 2422 { 2423 throw new VirtualDatabaseException(e); 2424 } 2425 } 2426 2427 2430 public String getDumpFormatForBackuper(String backuperName) 2431 { 2432 Backuper backuper = requestManager.getBackupManager().getBackuperByName( 2433 backuperName); 2434 if (backuper == null) 2435 { 2436 return null; 2437 } 2438 return backuper.getDumpFormat(); 2439 } 2440 2441 2444 public void initializeFromBackend(String databaseBackendName, boolean force) 2445 throws VirtualDatabaseException 2446 { 2447 RecoveryLog log = requestManager.getRecoveryLog(); 2448 if (log == null) 2449 throw new VirtualDatabaseException(Translate 2450 .get("virtualdatabase.no.recovery.log")); 2451 2452 try 2453 { 2454 int size = this.backends.size(); 2457 DatabaseBackend backendToInitializeFrom = null; 2458 for (int i = 0; i < size; i++) 2459 { 2460 DatabaseBackend dbe = (DatabaseBackend) backends.get(i); 2461 String backendName = dbe.getName(); 2462 if (backendName.equals(databaseBackendName)) 2463 { 2464 backendToInitializeFrom = dbe; 2465 } 2466 if (force) 2467 continue; 2468 BackendRecoveryInfo info = log 2469 .getBackendRecoveryInfo(name, backendName); 2470 if ((info.getBackendState() != BackendState.DISABLED) 2471 && (info.getBackendState() != BackendState.UNKNOWN)) 2472 throw new VirtualDatabaseException("Backend " + backendName 2473 + " is not in a disabled state (current state is " 2474 + BackendState.description(info.getBackendState()) + ")"); 2475 String checkpoint = info.getCheckpoint(); 2476 if ((checkpoint != null) && !checkpoint.equals("")) 2477 throw new VirtualDatabaseException("Backend " + backendName 2478 + " has a last known checkpoint (" + checkpoint + ")"); 2479 } 2480 if (backendToInitializeFrom == null) 2481 { 2482 throw new VirtualDatabaseException("backend " + databaseBackendName 2483 + " does not exist"); 2484 } 2485 log.resetRecoveryLog(); 2487 BackendRecoveryInfo info = log.getBackendRecoveryInfo(name, 2489 databaseBackendName); 2490 backendToInitializeFrom 2491 .setLastKnownCheckpoint("Initial_empty_recovery_log"); 2492 backendToInitializeFrom.setState(BackendState.DISABLED); 2493 info.setCheckpoint("Initial_empty_recovery_log"); 2494 info.setBackendState(BackendState.DISABLED); 2495 log.storeBackendRecoveryInfo(name, info); 2496 } 2497 catch (SQLException e) 2498 { 2499 throw new VirtualDatabaseException(e.getMessage()); 2500 } 2501 } 2502 2503 2509 public void removeCheckpoint(String checkpointName) 2510 throws VirtualDatabaseException 2511 { 2512 try 2513 { 2514 requestManager.removeCheckpoint(checkpointName); 2515 } 2516 catch (Exception e) 2517 { 2518 throw new VirtualDatabaseException(e.getMessage()); 2519 } 2520 } 2521 2522 2533 public void deleteDump(String dumpName, boolean keepsFile) 2534 throws VirtualDatabaseException 2535 { 2536 if (dumpName == null) 2537 { 2538 throw new VirtualDatabaseException("dump name can not be null"); 2539 } 2540 RecoveryLog recoveryLog = requestManager.getRecoveryLog(); 2541 if (recoveryLog == null) 2542 { 2543 throw new VirtualDatabaseException( 2544 "no recovery log for the virtual database" + getVirtualDatabaseName()); 2545 } 2546 DumpInfo dumpInfo; 2547 try 2548 { 2549 dumpInfo = recoveryLog.getDumpInfo(dumpName); 2550 } 2551 catch (SQLException e) 2552 { 2553 throw new VirtualDatabaseException(e); 2554 } 2555 if (dumpInfo == null) 2556 { 2557 throw new VirtualDatabaseException("Dump of name " + dumpName 2558 + " not found in the recovery log of virtual database " 2559 + getVirtualDatabaseName()); 2560 } 2561 Backuper backuper = requestManager.getBackupManager().getBackuperByFormat( 2562 dumpInfo.getDumpFormat()); 2563 if (backuper == null) 2564 { 2565 throw new VirtualDatabaseException("No backuper found for format " 2566 + dumpInfo.getDumpFormat() + " for the virtual database " 2567 + getVirtualDatabaseName()); 2568 } 2569 try 2570 { 2571 recoveryLog.removeDump(dumpInfo); 2572 } 2573 catch (SQLException e) 2574 { 2575 throw new VirtualDatabaseException(e); 2576 } 2577 if (!keepsFile) 2578 { 2579 try 2580 { 2581 backuper.deleteDump(dumpInfo.getDumpPath(), dumpInfo.getDumpName()); 2582 } 2583 catch (BackupException e) 2584 { 2585 throw new VirtualDatabaseException(e); 2586 } 2587 } 2588 } 2589 2590 2594 public void renameDump(String oldDumpName, String newDumpName) 2595 throws VirtualDatabaseException 2596 { 2597 try 2598 { 2599 RecoveryLog recoveryLog = requestManager.getRecoveryLog(); 2600 if (recoveryLog == null) 2601 throw new VirtualDatabaseException("No recovery log"); 2603 if (isDumpNameAvailable(oldDumpName)) 2604 throw new VirtualDatabaseException(oldDumpName + " does not exist"); 2605 2606 if (!isDumpNameAvailable(newDumpName)) 2607 throw new VirtualDatabaseException(newDumpName + " already exists"); 2608 2609 recoveryLog.updateDumpName(oldDumpName, newDumpName); 2610 } 2611 catch (SQLException e) 2612 { 2613 throw new VirtualDatabaseException(e); 2614 } 2615 } 2616 2617 2621 public void restoreDumpOnBackend(String databaseBackendName, String login, 2622 String password, String dumpName, ArrayList tables) 2623 throws VirtualDatabaseException 2624 { 2625 DatabaseBackend backend = getAndCheckBackend(databaseBackendName, 2626 NO_CHECK_BACKEND); 2627 2630 RestoreDumpOperation restoreOperation = new RestoreDumpOperation( 2631 databaseBackendName, dumpName); 2632 try 2633 { 2634 addAdminOperation(restoreOperation); 2635 requestManager.restoreBackendFromBackupCheckpoint(backend, login, 2636 password, dumpName, tables); 2637 } 2638 catch (BackupException e) 2639 { 2640 throw new VirtualDatabaseException(e); 2641 } 2642 finally 2643 { 2644 removeAdminOperation(restoreOperation); 2645 } 2646 } 2647 2648 2651 public void setBackendLastKnownCheckpoint(String backendName, 2652 String checkpoint) throws VirtualDatabaseException 2653 { 2654 RecoveryLog log = requestManager.getRecoveryLog(); 2655 DatabaseBackend backend = getAndCheckBackend(backendName, NO_CHECK_BACKEND); 2656 if (log == null) 2657 throw new VirtualDatabaseException("No recovery log has been defined"); 2658 else 2659 { 2660 if (!backend.isDisabled()) 2661 throw new VirtualDatabaseException( 2662 "Cannot setLastKnownCheckpoint on a non-disabled backend"); 2663 else 2664 { 2665 try 2666 { 2667 log.storeBackendRecoveryInfo(this.name, 2668 new BackendRecoveryInfo(backend.getName(), checkpoint, backend 2669 .getStateValue(), this.name)); 2670 2671 backend.setLastKnownCheckpoint(checkpoint); 2672 } 2673 catch (SQLException e) 2674 { 2675 throw new VirtualDatabaseException( 2676 "Failed to store recovery info for backend '" + backendName 2677 + "' (" + e + ")"); 2678 } 2679 } 2680 } 2681 } 2682 2683 2686 public void setShutdownCheckpoint() 2687 { 2688 RecoveryLog recoveryLog = requestManager.getRecoveryLog(); 2689 if (recoveryLog != null) 2690 try 2691 { 2692 recoveryLog 2693 .storeCheckpoint("shutdown" + controller.getControllerName()); 2694 } 2695 catch (SQLException e) 2696 { 2697 logger.warn("Error while setting shutdown checkpoint", e); 2698 } 2699 } 2700 2701 2705 public void transferDump(String dumpName, String remoteControllerName, 2706 boolean noCopy) throws VirtualDatabaseException 2707 { 2708 if (!isDistributed()) 2709 throw new VirtualDatabaseException( 2710 "can not transfer dumps on non-distributed virtual database"); 2711 } 2712 2713 2717 public void updateDumpPath(String dumpName, String newPath) 2718 throws VirtualDatabaseException 2719 { 2720 try 2721 { 2722 RecoveryLog recoveryLog = requestManager.getRecoveryLog(); 2723 if (recoveryLog == null) 2724 { 2725 throw new VirtualDatabaseException("no recovery log"); } 2727 else 2728 { 2729 recoveryLog.updateDumpPath(dumpName, newPath); 2730 } 2731 } 2732 catch (SQLException e) 2733 { 2734 throw new VirtualDatabaseException(e); 2735 } 2736 } 2737 2738 2743 public void addVirtualDatabaseWorkerThread(VirtualDatabaseWorkerThread thread) 2744 { 2745 synchronized (activeThreads) 2746 { 2747 activeThreads.add(thread); 2748 incrementCurrentNbOfThread(); 2749 } 2750 } 2751 2752 2756 protected void decreaseCurrentNbOfThread() 2757 { 2758 currentNbOfThreads--; 2759 } 2760 2761 2765 protected void decreaseIdleThread() 2766 { 2767 idleThreads--; 2768 } 2769 2770 2773 public int getCurrentNbOfThreads() 2774 { 2775 return currentNbOfThreads; 2776 } 2777 2778 2784 public int getIdleThreads() 2785 { 2786 return idleThreads; 2787 } 2788 2789 2794 public int getMaxNbOfThreads() 2795 { 2796 return maxNbOfThreads; 2797 } 2798 2799 2804 public long getMaxThreadIdleTime() 2805 { 2806 return maxThreadIdleTime; 2807 } 2808 2809 2814 public int getMinNbOfThreads() 2815 { 2816 return minNbOfThreads; 2817 } 2818 2819 2823 2831 public VirtualDatabaseWorkerThread getVirtualDatabaseWorkerThreadForTransaction( 2832 long transactionId) 2833 { 2834 synchronized (activeThreads) 2835 { 2836 for (Iterator iter = activeThreads.iterator(); iter.hasNext();) 2837 { 2838 VirtualDatabaseWorkerThread vdbwt = (VirtualDatabaseWorkerThread) iter 2839 .next(); 2840 if (vdbwt.getCurrentTransactionId() == transactionId) 2841 return vdbwt; 2842 } 2843 } 2844 return null; 2845 } 2846 2847 2850 protected void incrementCurrentNbOfThread() 2851 { 2852 currentNbOfThreads++; 2853 } 2854 2855 2859 protected void incrementIdleThreadCount() 2860 { 2861 idleThreads++; 2862 } 2863 2864 2869 public boolean isPoolConnectionThreads() 2870 { 2871 return poolConnectionThreads; 2872 } 2873 2874 2879 public void setMaxThreadIdleTime(long maxThreadIdleTime) 2880 { 2881 this.maxThreadIdleTime = maxThreadIdleTime; 2882 } 2883 2884 2889 public void setMinNbOfThreads(int minNbOfThreads) 2890 { 2891 this.minNbOfThreads = minNbOfThreads; 2892 } 2893 2894 2899 public void setPoolConnectionThreads(boolean poolConnectionThreads) 2900 { 2901 this.poolConnectionThreads = poolConnectionThreads; 2902 } 2903 2904 2908 2913 public ArrayList getActiveThreads() 2914 { 2915 return activeThreads; 2916 } 2917 2918 2923 public AuthenticationManager getAuthenticationManager() 2924 { 2925 return authenticationManager; 2926 } 2927 2928 2931 public String getBackendInformation(String backendName) 2932 throws VirtualDatabaseException 2933 { 2934 try 2935 { 2936 acquireReadLockBackendLists(); 2937 } 2938 catch (InterruptedException e) 2939 { 2940 String msg = "Unable to acquire read lock on backend list in getBackendInformation (" 2941 + e + ")"; 2942 logger.error(msg); 2943 throw new VirtualDatabaseException(msg); 2944 } 2945 2946 int size = backends.size(); 2948 DatabaseBackend b = null; 2949 for (int i = 0; i < size; i++) 2950 { 2951 b = (DatabaseBackend) backends.get(i); 2952 if (b.getName().equals(backendName)) 2953 break; 2954 else 2955 b = null; 2956 } 2957 2958 if (b == null) 2959 { 2960 releaseReadLockBackendLists(); 2961 String msg = "Backend " + backendName + " does not exists."; 2962 logger.warn(msg); 2963 throw new VirtualDatabaseException(msg); 2964 } 2965 2966 releaseReadLockBackendLists(); 2967 return b.getXml(); 2968 } 2969 2970 2975 public ArrayList getBackends() 2976 { 2977 return backends; 2978 } 2979 2980 2989 public SQLWarning getConnectionWarnings(long connId) throws SQLException 2990 { 2991 DatabaseBackend b = getFirstAvailableBackend(); 2992 return b.getPersistentConnectionWarnings(connId); 2993 } 2994 2995 3002 public void clearConnectionWarnings(long connId) throws SQLException 3003 { 3004 if (backends == null) 3006 return; 3007 try 3008 { 3009 for (Iterator iter = backends.iterator(); iter.hasNext();) 3010 { 3011 DatabaseBackend b = (DatabaseBackend) iter.next(); 3012 if (b.isWriteEnabled() && b.isJDBCConnected()) 3013 b.clearPersistentConnectionWarnings(connId); 3014 } 3015 } 3016 catch (ConcurrentModificationException e) 3017 { 3018 clearConnectionWarnings(connId); 3020 } 3021 } 3022 3023 3031 public String getDatabaseName() 3032 { 3033 return name; 3034 } 3035 3036 3039 public String getDatabaseProductName() 3040 { 3041 return databaseProductNames; 3042 } 3043 3044 3048 public VirtualDatabaseDynamicMetaData getDynamicMetaData() 3049 { 3050 if (metadata == null) 3051 { 3052 metadata = new VirtualDatabaseDynamicMetaData(this); 3053 } 3054 return metadata; 3055 } 3056 3057 3062 public final DynamicDatabaseSchema getDynamicDatabaseSchema() 3063 { 3064 return dynamicDatabaseSchema; 3065 } 3066 3067 3072 public final void setDynamicDatabaseSchema( 3073 DynamicDatabaseSchema dynamicDatabaseSchema) 3074 { 3075 this.dynamicDatabaseSchema = dynamicDatabaseSchema; 3076 } 3077 3078 3085 public DatabaseSchema getDatabaseSchemaFromActiveBackends() 3086 throws SQLException 3087 { 3088 boolean isRaidb1 = requestManager.getLoadBalancer().getRAIDbLevel() == RAIDbLevels.RAIDb1; 3089 3090 try 3091 { 3092 acquireReadLockBackendLists(); 3093 } 3094 catch (InterruptedException e) 3095 { 3096 String msg = "Unable to acquire read lock on backend list in getDatabaseSchemaFromActiveBackends (" 3097 + e + ")"; 3098 logger.error(msg); 3099 throw new SQLException (msg); 3100 } 3101 3102 DatabaseSchema schema = null; 3103 try 3104 { 3105 int size = backends.size(); 3107 DatabaseBackend b = null; 3108 for (int i = 0; i < size; i++) 3109 { 3110 b = (DatabaseBackend) backends.get(i); 3111 if (b.isReadEnabled()) 3112 { 3113 DatabaseSchema backendSchema = b.getDatabaseSchema(); 3114 if (backendSchema != null) 3115 { if (schema == null) 3117 schema = new DatabaseSchema(backendSchema); 3118 else 3119 schema.mergeSchema(backendSchema); 3120 3121 if (isRaidb1) 3124 break; 3125 } 3126 } 3127 } 3128 3129 } 3132 finally 3133 { 3134 releaseReadLockBackendLists(); 3135 } 3136 3137 return schema; 3138 } 3139 3140 3147 public DatabaseSchema getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames() 3148 throws SQLException 3149 { 3150 try 3151 { 3152 acquireReadLockBackendLists(); 3153 } 3154 catch (InterruptedException e) 3155 { 3156 String msg = "Unable to acquire read lock on backend list in getDatabaseSchemaFromActiveBackendsAndRefreshDatabaseProductNames (" 3157 + e + ")"; 3158 logger.error(msg); 3159 throw new SQLException (msg); 3160 } 3161 3162 DatabaseSchema schema = null; 3163 String dbProductNames = "Sequoia"; 3164 try 3165 { 3166 int size = backends.size(); 3168 DatabaseBackend b = null; 3169 for (int i = 0; i < size; i++) 3170 { 3171 b = (DatabaseBackend) backends.get(i); 3172 if (b.isReadEnabled()) 3173 { 3174 DatabaseSchema backendSchema = b.getDatabaseSchema(); 3175 if (backendSchema != null) 3176 { if (schema == null) 3178 schema = new DatabaseSchema(backendSchema); 3179 else 3180 schema.mergeSchema(backendSchema); 3181 } 3182 } 3183 3184 if (dbProductNames.indexOf(b.getDatabaseProductName()) == -1) 3186 dbProductNames += "," + b.getDatabaseProductName(); 3187 } 3188 } 3189 finally 3190 { 3191 releaseReadLockBackendLists(); 3192 } 3193 databaseProductNames = dbProductNames; 3194 3195 3198 return schema; 3199 } 3200 3201 3206 DatabaseBackend getFirstAvailableBackend() 3207 { 3208 if (backends == null) 3210 return null; 3211 try 3212 { 3213 for (Iterator iter = backends.iterator(); iter.hasNext();) 3214 { 3215 DatabaseBackend b = (DatabaseBackend) iter.next(); 3216 if (b.isReadEnabled() && b.isJDBCConnected()) 3217 return b; 3218 } 3219 } 3220 catch (ConcurrentModificationException e) 3221 { 3222 return getFirstAvailableBackend(); 3223 } 3224 3225 return null; 3226 } 3227 3228 3233 public final Trace getLogger() 3234 { 3235 return logger; 3236 } 3237 3238 3243 public int getMaxNbOfConnections() 3244 { 3245 return maxNbOfConnections; 3246 } 3247 3248 3256 public int getNumberOfSavepointsInTransaction(long tId) 3257 { 3258 return requestManager.getNumberOfSavepointsInTransaction(tId); 3259 } 3260 3261 3266 public ArrayList getPendingConnections() 3267 { 3268 return pendingConnections; 3269 } 3270 3271 3276 public RequestManager getRequestManager() 3277 { 3278 return requestManager; 3279 } 3280 3281 3286 public final SemanticManager getSemanticManager() 3287 { 3288 return semanticManager; 3289 } 3290 3291 3298 public VirtualDatabaseStaticMetaData getStaticMetaData() 3299 { 3300 return doGetStaticMetaData(); 3301 } 3302 3303 3306 public VirtualDatabaseStaticMetaData doGetStaticMetaData() 3307 { 3308 if (staticMetadata == null) 3309 { 3310 staticMetadata = new VirtualDatabaseStaticMetaData(this); 3311 } 3312 return staticMetadata; 3313 } 3314 3315 3320 public String getVirtualDatabaseName() 3321 { 3322 return name; 3323 } 3324 3325 3331 public SQLMonitoring getSQLMonitor() 3332 { 3333 return sqlMonitor; 3334 } 3335 3336 3342 public int getSqlShortFormLength() 3343 { 3344 return sqlShortFormLength; 3345 } 3346 3347 3352 public LinkedList getTotalOrderQueue() 3353 { 3354 return totalOrderQueue; 3355 } 3356 3357 3360 public boolean hasRecoveryLog() 3361 { 3362 RecoveryLog log = requestManager.getRecoveryLog(); 3363 if (log == null) 3364 return false; 3365 else 3366 return true; 3367 } 3368 3369 3372 public boolean hasResultCache() 3373 { 3374 AbstractResultCache cache = requestManager.getResultCache(); 3375 if (cache == null) 3376 return false; 3377 else 3378 return true; 3379 } 3380 3381 3387 public void setAuthenticationManager( 3388 AuthenticationManager authenticationManager) 3389 { 3390 this.authenticationManager = authenticationManager; 3391 } 3392 3393 3398 public void setMaxNbOfConnections(int maxNbOfConnections) 3399 { 3400 this.maxNbOfConnections = maxNbOfConnections; 3401 } 3402 3403 3408 public void setMaxNbOfThreads(int maxNbOfThreads) 3409 { 3410 this.maxNbOfThreads = maxNbOfThreads; 3411 } 3412 3413 3418 public void setRequestManager(RequestManager requestManager) 3419 { 3420 this.requestManager = requestManager; 3421 } 3422 3423 3428 public void setSQLMonitor(SQLMonitoring sqlMonitor) 3429 { 3430 this.sqlMonitor = sqlMonitor; 3431 } 3432 3433 3436 public void setMonitoringToActive(boolean active) 3437 throws VirtualDatabaseException 3438 { 3439 if (sqlMonitor == null) 3440 throw new VirtualDatabaseException(Translate 3441 .get("virtualdatabase.monitoring.not.defined")); 3442 else 3443 sqlMonitor.setActive(active); 3444 } 3445 3446 3451 public final boolean useStaticResultSetMetaData() 3452 { 3453 return useStaticResultSetMetaData; 3454 } 3455 3456 3462 public boolean equals(Object other) 3463 { 3464 if ((other == null) || (!(other instanceof VirtualDatabase))) 3465 return false; 3466 else 3467 { 3468 VirtualDatabase db = (VirtualDatabase) other; 3469 return name.equals(db.getDatabaseName()); 3470 } 3471 } 3472 3473 3477 3480 public BackendStatistics getBackendStatistics(String backendName) 3481 throws VirtualDatabaseException 3482 { 3483 try 3484 { 3485 acquireReadLockBackendLists(); 3486 } 3487 catch (InterruptedException e) 3488 { 3489 String msg = Translate.get("virtualdatabase.fail.read.lock", e); 3490 throw new VirtualDatabaseException(msg); 3491 } 3492 BackendStatistics stat = null; 3493 ArrayList backendList = this.getBackends(); 3494 for (Iterator iter = backendList.iterator(); iter.hasNext();) 3495 { 3496 DatabaseBackend backend = (DatabaseBackend) iter.next(); 3497 if (backend.getName().equals(backendName)) 3498 { 3499 stat = backend.getBackendStats(); 3500 } 3501 } 3502 releaseReadLockBackendLists(); 3503 return stat; 3504 } 3505 3506 3511 protected void addAdminOperation(AbstractAdminOperation operation) 3512 { 3513 synchronized (currentAdminOperations) 3514 { 3515 currentAdminOperations.add(operation); 3516 } 3517 } 3518 3519 3526 protected boolean removeAdminOperation(AbstractAdminOperation operation) 3527 { 3528 synchronized (currentAdminOperations) 3529 { 3530 currentAdminOperations.notify(); 3531 return currentAdminOperations.remove(operation); 3532 } 3533 } 3534 3535 3538 private void waitForAdminOperationsToComplete() 3539 { 3540 synchronized (currentAdminOperations) 3541 { 3542 while (!currentAdminOperations.isEmpty()) 3543 { 3544 for (Iterator iter = currentAdminOperations.iterator(); iter.hasNext();) 3545 { 3546 AbstractAdminOperation op = (AbstractAdminOperation) iter.next(); 3547 logger.info("Waiting for command '" + op + "' to complete"); 3548 } 3549 try 3550 { 3551 currentAdminOperations.wait(); 3552 } 3553 catch (InterruptedException ignore) 3554 { 3555 } 3556 } 3557 } 3558 } 3559 3560 3564 3569 public boolean isShuttingDown() 3570 { 3571 return shuttingDown; 3572 } 3573 3574 3579 public void setShuttingDown(boolean shuttingDown) 3580 { 3581 this.shuttingDown = shuttingDown; 3582 } 3583 3584 public boolean isRejectingNewTransaction() 3585 { 3586 return refusingNewTransaction; 3587 } 3588 3589 public void setRejectingNewTransaction(boolean canAcceptNewTransaction) 3590 { 3591 this.refusingNewTransaction = canAcceptNewTransaction; 3592 } 3593 3594 3597 public void shutdown(int level) 3598 { 3599 VirtualDatabaseShutdownThread vdst = null; 3600 String msg = Translate.get("virtualdatabase.shutting.down", this 3601 .getVirtualDatabaseName()); 3602 synchronized (this) 3603 { 3604 if (shuttingDown && !(level == Constants.SHUTDOWN_FORCE)) 3605 return; 3606 switch (level) 3607 { 3608 case Constants.SHUTDOWN_WAIT : 3609 vdst = new VirtualDatabaseWaitShutdownThread(this); 3610 msg = Translate.get("virtualdatabase.shutdown.type.wait", this 3611 .getVirtualDatabaseName()); 3612 logger.info(msg); 3613 endUserLogger.info(msg); 3614 break; 3615 case Constants.SHUTDOWN_SAFE : 3616 shuttingDown = true; 3617 vdst = new VirtualDatabaseSafeShutdownThread(this); 3618 msg = Translate.get("virtualdatabase.shutdown.type.safe", this 3619 .getVirtualDatabaseName()); 3620 logger.info(msg); 3621 endUserLogger.info(msg); 3622 break; 3623 case Constants.SHUTDOWN_FORCE : 3624 shuttingDown = true; 3625 vdst = new VirtualDatabaseForceShutdownThread(this); 3626 msg = Translate.get("virtualdatabase.shutdown.type.force", this 3627 .getVirtualDatabaseName()); 3628 logger.warn(msg); 3629 endUserLogger.info(msg); 3630 break; 3631 default : 3632 msg = Translate.get("virtualdatabase.shutdown.unknown.level", 3633 new Object []{new Integer (level), this.getVirtualDatabaseName()}); 3634 logger.error(msg); 3635 endUserLogger.error(msg); 3636 throw new RuntimeException (msg); 3637 } 3638 } 3639 3640 if (level != Constants.SHUTDOWN_FORCE) 3641 { 3642 waitForAdminOperationsToComplete(); 3644 } 3645 3646 Thread thread = new Thread (vdst.getShutdownGroup(), vdst, 3647 "VirtualDatabase Shutdown Thread"); 3648 thread.start(); 3649 try 3650 { 3651 logger.info("Waiting for virtual database " + name + " shutdown"); 3652 thread.join(); 3653 controller.removeVirtualDatabase(name); 3654 msg = Translate.get("notification.virtualdatabase.shutdown", name); 3655 logger.info(msg); 3656 endUserLogger.info(msg); 3657 3658 try 3659 { 3660 MBeanServerManager.unregister(JmxConstants 3661 .getVirtualDataBaseObjectName(name)); 3662 if (hasRecoveryLog()) MBeanServerManager.unregister(JmxConstants 3664 .getRecoveryLogObjectName(name)); 3665 MBeanServerManager.unregister(JmxConstants 3666 .getAbstractSchedulerObjectName(name)); 3667 MBeanServerManager.unregister(JmxConstants 3668 .getLoadBalancerObjectName(name)); 3669 MBeanServerManager.unregister(JmxConstants 3670 .getRequestManagerObjectName(name)); 3671 ArrayList backendNames = getAllBackendNames(); 3672 for (int i = 0; i < backendNames.size(); i++) 3673 { 3674 String backendName = (String ) backendNames.get(i); 3675 MBeanServerManager.unregister(JmxConstants 3676 .getDatabaseBackendObjectName(name, backendName)); 3677 } 3678 } 3679 catch (Exception e) 3680 { 3681 logger.error(Translate.get("virtualdatabase.fail.unregister.mbean", 3682 name), e); 3683 } 3684 } 3685 catch (InterruptedException e) 3686 { 3687 e.printStackTrace(); 3688 } 3689 } 3690 3691 3694 public void storeBackendsInfo() 3695 { 3696 requestManager.storeBackendsInfo(this.name, getBackends()); 3697 } 3698 3699 3705 public ArrayList viewAllClientNames() 3706 { 3707 ArrayList list = this.getActiveThreads(); 3708 int size = list.size(); 3709 ArrayList clients = new ArrayList (size); 3710 for (int i = 0; i < list.size(); i++) 3711 clients.add(((VirtualDatabaseWorkerThread) list.get(i)).getUser()); 3712 return clients; 3713 } 3714 3715 3718 public String [] viewControllerList() 3719 { 3720 return new String []{viewOwningController()}; 3721 } 3722 3723 3726 public String viewOwningController() 3727 { 3728 return controller.getJmxName(); 3729 } 3730 3731 3736 public String getXml() 3737 { 3738 StringBuffer info = new StringBuffer (); 3739 info.append("<" + DatabasesXmlTags.ELT_VirtualDatabase + " " 3740 + DatabasesXmlTags.ATT_name + "=\"" + this.getVirtualDatabaseName() 3741 + "\" " + DatabasesXmlTags.ATT_maxNbOfConnections + "=\"" 3742 + this.getMaxNbOfConnections() + "\" " 3743 + DatabasesXmlTags.ATT_poolThreads + "=\"" 3744 + this.isPoolConnectionThreads() + "\" " 3745 + DatabasesXmlTags.ATT_minNbOfThreads + "=\"" 3746 + this.getMinNbOfThreads() + "\" " 3747 + DatabasesXmlTags.ATT_maxNbOfThreads + "=\"" 3748 + this.getMaxNbOfThreads() + "\" " 3749 + DatabasesXmlTags.ATT_maxThreadIdleTime + "=\"" 3750 + this.getMaxThreadIdleTime() / 1000 + "\" " 3751 + DatabasesXmlTags.ATT_sqlDumpLength + "=\"" + this.sqlShortFormLength 3752 + "\">"); 3753 3754 info.append(getDistributionXml()); 3755 3756 if (this.getSQLMonitor() != null) 3757 info.append(sqlMonitor.getXml()); 3758 3759 info.append(requestManager.getBackupManager().getXml()); 3760 3761 if (this.getAuthenticationManager() != null) 3762 info.append(authenticationManager.getXml()); 3763 3764 try 3765 { 3766 acquireReadLockBackendLists(); 3767 int size = backends.size(); 3768 for (int i = 0; i < size; i++) 3769 info.append(((DatabaseBackend) backends.get(i)).getXml()); 3770 releaseReadLockBackendLists(); 3771 } 3772 catch (InterruptedException e) 3773 { 3774 logger.error(Translate.get("virtualdatabase.fail.read.lock", e)); 3775 } 3776 3777 if (this.getDynamicDatabaseSchema() != null) 3778 info.append(getDynamicDatabaseSchema().getXml()); 3779 3780 if (this.getSemanticManager() != null) 3781 info.append(getSemanticManager().getXml()); 3782 3783 if (requestManager != null) 3784 info.append(requestManager.getXml()); 3785 info.append("</" + DatabasesXmlTags.ELT_VirtualDatabase + ">"); 3786 return info.toString(); 3787 } 3788 3789 3794 protected String getDistributionXml() 3795 { 3796 return ""; 3797 } 3798} | Popular Tags |