1 24 25 package org.continuent.sequoia.controller.backend; 26 27 import java.io.StringReader ; 28 import java.net.ConnectException ; 29 import java.sql.Connection ; 30 import java.sql.SQLException ; 31 import java.sql.SQLWarning ; 32 import java.sql.Savepoint ; 33 import java.sql.Statement ; 34 import java.util.ArrayList ; 35 import java.util.Collection ; 36 import java.util.Date ; 37 import java.util.HashMap ; 38 import java.util.Iterator ; 39 import java.util.List ; 40 import java.util.Map ; 41 import java.util.Vector ; 42 43 import javax.management.AttributeChangeNotification ; 44 import javax.management.MalformedObjectNameException ; 45 import javax.management.Notification ; 46 import javax.management.NotificationBroadcasterSupport ; 47 48 import org.continuent.sequoia.common.exceptions.NoTransactionStartWhenDisablingException; 49 import org.continuent.sequoia.common.exceptions.UnreachableBackendException; 50 import org.continuent.sequoia.common.exceptions.VirtualDatabaseException; 51 import org.continuent.sequoia.common.i18n.Translate; 52 import org.continuent.sequoia.common.jmx.JmxConstants; 53 import org.continuent.sequoia.common.jmx.management.BackendInfo; 54 import org.continuent.sequoia.common.jmx.management.BackendState; 55 import org.continuent.sequoia.common.jmx.monitoring.backend.BackendStatistics; 56 import org.continuent.sequoia.common.jmx.notifications.SequoiaNotificationList; 57 import org.continuent.sequoia.common.log.Trace; 58 import org.continuent.sequoia.common.sql.metadata.MetadataContainer; 59 import org.continuent.sequoia.common.users.VirtualDatabaseUser; 60 import org.continuent.sequoia.common.xml.DatabasesXmlTags; 61 import org.continuent.sequoia.common.xml.XmlComponent; 62 import org.continuent.sequoia.controller.backend.rewriting.AbstractRewritingRule; 63 import org.continuent.sequoia.controller.connection.AbstractConnectionManager; 64 import org.continuent.sequoia.controller.connection.DriverManager; 65 import org.continuent.sequoia.controller.connection.FailFastPoolConnectionManager; 66 import org.continuent.sequoia.controller.connection.PooledConnection; 67 import org.continuent.sequoia.controller.connection.RandomWaitPoolConnectionManager; 68 import org.continuent.sequoia.controller.connection.SimpleConnectionManager; 69 import org.continuent.sequoia.controller.connection.VariablePoolConnectionManager; 70 import org.continuent.sequoia.controller.core.ControllerConstants; 71 import org.continuent.sequoia.controller.loadbalancer.AbstractLoadBalancer; 72 import org.continuent.sequoia.controller.loadbalancer.BackendTaskQueues; 73 import org.continuent.sequoia.controller.loadbalancer.BackendWorkerThread; 74 import org.continuent.sequoia.controller.loadbalancer.tasks.AbstractTask; 75 import org.continuent.sequoia.controller.loadbalancer.tasks.KillThreadTask; 76 import org.continuent.sequoia.controller.requests.AbstractRequest; 77 import org.continuent.sequoia.controller.requests.AbstractWriteRequest; 78 import org.continuent.sequoia.controller.requests.StoredProcedure; 79 import org.continuent.sequoia.controller.semantic.SemanticBehavior; 80 import org.continuent.sequoia.controller.sql.schema.DatabaseSchema; 81 import org.continuent.sequoia.controller.sql.schema.DatabaseTable; 82 import org.continuent.sequoia.controller.sql.schema.DynamicDatabaseSchema; 83 import org.continuent.sequoia.controller.virtualdatabase.VirtualDatabase; 84 import org.dom4j.Document; 85 import org.dom4j.Element; 86 import org.dom4j.io.SAXReader; 87 88 102 public final class DatabaseBackend implements XmlComponent 103 { 104 117 118 private String name; 119 120 121 private String driverPath; 122 123 124 private String driverClassName; 125 126 127 private transient DriverCompliance driverCompliance; 128 129 130 private String url; 131 132 133 private VirtualDatabase vdb; 134 135 136 private boolean writeCanBeEnabled; 137 138 139 private String connectionTestStatement; 140 141 145 private transient DatabaseSchema schema; 146 147 148 private boolean schemaIsDirty = true; 149 150 151 private transient Map connectionManagers; 152 153 154 private Map persistentConnections; 155 156 157 protected transient Trace logger; 158 159 163 private transient ArrayList activeTransactions = new ArrayList (); 164 165 166 private transient Map savepoints = new HashMap (); 167 168 169 private transient Vector pendingRequests = new Vector (); 170 171 172 private transient Vector pendingTasks = new Vector (); 173 174 175 private transient BackendTaskQueues taskQueues = null; 176 177 private int nbOfWorkerThreads = 5; 178 private ArrayList workerThreads = null; 179 private final Object workerThreadSync = new Object (); 180 181 182 private int totalRequest; 183 private int totalWriteRequest; 184 private int totalReadRequest; 185 private int totalTransactions; 186 187 188 private ArrayList rewritingRules; 189 190 191 private int dynamicPrecision = -1; 192 193 194 private int sqlShortFormLength = 40; 195 196 private String lastKnownCheckpoint; 197 198 203 private int state = BackendState.DISABLED; 204 205 private transient BackendStateListener stateListener; 206 207 private NotificationBroadcasterSupport notificationBroadcaster; 208 209 private int notificationSequence = 0; 210 211 private int totalTasks; 212 213 private AbstractConnectionManager defaultConnectionManager = null; 214 215 216 static Trace endUserLogger = Trace 217 .getLogger("org.continuent.sequoia.enduser"); 218 219 234 public DatabaseBackend(VirtualDatabase vdb, String name, String driverPath, 235 String driverClassName, String url, boolean writeCanBeEnabled, 236 String connectionTestStatement, int nbOfWorkerThreads) 237 { 238 if (name == null) 239 throw new IllegalArgumentException (Translate 240 .get("backend.null.backend.name")); 241 242 if (driverClassName == null) 243 throw new IllegalArgumentException (Translate.get("backend.null.driver")); 244 245 if (url == null) 246 throw new IllegalArgumentException (Translate.get("backend.null.url")); 247 248 if (vdb == null) 249 throw new IllegalArgumentException (Translate 250 .get("backend.null.virtualdatabase")); 251 252 if (connectionTestStatement == null) 253 throw new IllegalArgumentException (Translate 254 .get("backend.null.connection.test")); 255 256 logger = Trace 257 .getLogger("org.continuent.sequoia.controller.backend.DatabaseBackend." 258 + name); 259 260 if (nbOfWorkerThreads < 2) 261 { 262 nbOfWorkerThreads = 2; 263 logger.warn("Invalid number of worker threads (" + nbOfWorkerThreads 264 + "), re-adjusting to the minimum (2)."); 265 } 266 267 this.name = name; 268 this.writeCanBeEnabled = writeCanBeEnabled; 269 this.driverPath = driverPath; 270 this.driverClassName = driverClassName; 271 this.url = url; 272 this.vdb = vdb; 273 this.connectionTestStatement = connectionTestStatement; 274 this.nbOfWorkerThreads = nbOfWorkerThreads; 275 this.connectionManagers = new HashMap (); 276 this.persistentConnections = new HashMap (); 277 this.driverCompliance = new DriverCompliance(logger); 278 totalRequest = 0; 279 } 280 281 286 public DatabaseBackend(VirtualDatabase vdb, BackendInfo info) 287 { 288 this(vdb, info.getName(), info.getDriverPath(), info.getDriverClassName(), 289 info.getUrl(), true, info.getConnectionTestStatement(), info 290 .getNbOfWorkerThreads()); 291 try 292 { 293 String xml = info.getXml(); 294 StringReader sreader = new StringReader (xml); 295 SAXReader reader = new SAXReader(); 296 Document document = reader.read(sreader); 297 Element root = document.getRootElement(); 298 Iterator iter1 = root.elementIterator(); 299 while (iter1.hasNext()) 300 { 301 Element elem = (Element) iter1.next(); 302 if (elem.getName().equals(DatabasesXmlTags.ELT_ConnectionManager)) 303 { 304 String vuser = elem.valueOf("@" + DatabasesXmlTags.ATT_vLogin); 305 String rlogin = elem.valueOf("@" + DatabasesXmlTags.ATT_rLogin); 306 String rpassword = elem.valueOf("@" + DatabasesXmlTags.ATT_rPassword); 307 Iterator iter2 = elem.elementIterator(); 308 while (iter2.hasNext()) 309 { 310 Element connectionManager = (Element) iter2.next(); 311 String cname = connectionManager.getName(); 312 if (cname 313 .equals(DatabasesXmlTags.ELT_VariablePoolConnectionManager)) 314 { 315 int minPoolSize = Integer.parseInt(connectionManager.valueOf("@" 316 + DatabasesXmlTags.ATT_minPoolSize)); 317 int maxPoolSize = Integer.parseInt(connectionManager.valueOf("@" 318 + DatabasesXmlTags.ATT_maxPoolSize)); 319 int idleTimeout = Integer.parseInt(connectionManager.valueOf("@" 320 + DatabasesXmlTags.ATT_idleTimeout)); 321 int waitTimeout = Integer.parseInt(connectionManager.valueOf("@" 322 + DatabasesXmlTags.ATT_waitTimeout)); 323 this.addConnectionManager(vuser, 324 new VariablePoolConnectionManager(url, name, rlogin, 325 rpassword, driverPath, driverClassName, minPoolSize, 326 maxPoolSize, idleTimeout, waitTimeout)); 327 } 328 else if (cname.equals(DatabasesXmlTags.ELT_SimpleConnectionManager)) 329 { 330 this.addConnectionManager(vuser, new SimpleConnectionManager(url, 331 name, rlogin, rpassword, driverPath, driverClassName)); 332 } 333 else if (cname 334 .equals(DatabasesXmlTags.ELT_RandomWaitPoolConnectionManager)) 335 { 336 int poolSize = Integer.parseInt(connectionManager.valueOf("@" 337 + DatabasesXmlTags.ATT_poolSize)); 338 int timeout = Integer.parseInt(connectionManager.valueOf("@" 339 + DatabasesXmlTags.ATT_timeout)); 340 this 341 .addConnectionManager(vuser, 342 new RandomWaitPoolConnectionManager(url, name, rlogin, 343 rpassword, driverPath, driverClassName, poolSize, 344 timeout)); 345 346 } 347 else if (cname 348 .equals(DatabasesXmlTags.ELT_FailFastPoolConnectionManager)) 349 { 350 int poolSize = Integer.parseInt(connectionManager.valueOf("@" 351 + DatabasesXmlTags.ATT_poolSize)); 352 this.addConnectionManager(vuser, 353 new FailFastPoolConnectionManager(url, name, rlogin, 354 rpassword, driverPath, driverClassName, poolSize)); 355 } 356 } 357 } 358 } 359 360 } 361 catch (Exception e) 362 { 363 logger 364 .error(Translate.get("backend.add.connection.manager.failed", e), e); 365 } 366 } 367 368 388 public DatabaseBackend copy(String newName, Map parameters) throws Exception 389 { 390 String fromDriverPath = parameters 393 .containsKey(DatabasesXmlTags.ATT_driverPath) ? (String ) parameters 394 .get(DatabasesXmlTags.ATT_driverPath) : this.getDriverPath(); 395 396 String fromDriverClassName = parameters 397 .containsKey(DatabasesXmlTags.ATT_driver) ? (String ) parameters 398 .get(DatabasesXmlTags.ATT_driver) : this.getDriverClassName(); 399 400 String fromUrl = parameters.containsKey(DatabasesXmlTags.ATT_url) 401 ? (String ) parameters.get(DatabasesXmlTags.ATT_url) 402 403 : this.getURL(); 404 405 String fromConnectionTestStatement = parameters 406 .containsKey(DatabasesXmlTags.ATT_connectionTestStatement) 407 ? (String ) parameters.get(DatabasesXmlTags.ATT_connectionTestStatement) 408 : this.getConnectionTestStatement(); 409 410 if (getURL().equals(fromUrl) 411 && getDriverClassName().equals(fromDriverClassName)) 412 throw new VirtualDatabaseException( 413 "It is not allowed to clone a backend with the same URL and driver class name"); 414 415 DatabaseBackend newBackend = new DatabaseBackend(vdb, newName, 417 fromDriverPath, fromDriverClassName, fromUrl, writeCanBeEnabled, 418 fromConnectionTestStatement, nbOfWorkerThreads); 419 420 newBackend.rewritingRules = this.rewritingRules; 423 424 Map fromConnectionManagers = this.connectionManagers; 426 Iterator iter = fromConnectionManagers.keySet().iterator(); 427 428 String vlogin = null; 429 AbstractConnectionManager connectionManager; 430 while (iter.hasNext()) 431 { 432 vlogin = (String ) iter.next(); 433 connectionManager = (AbstractConnectionManager) fromConnectionManagers 434 .get(vlogin); 435 newBackend.addConnectionManager(vlogin, connectionManager.copy(fromUrl, 436 newName)); 437 } 438 439 return newBackend; 440 } 441 442 449 public boolean equals(Object other) 450 { 451 if ((other == null) || (!(other instanceof DatabaseBackend))) 452 return false; 453 else 454 { 455 DatabaseBackend b = (DatabaseBackend) other; 456 return name.equals(b.getName()) 457 && driverClassName.equals(b.getDriverClassName()) 458 && url.equals(b.getURL()); 459 } 460 } 461 462 465 public int hashCode() 466 { 467 return name.hashCode(); 468 } 469 470 474 481 public void addConnectionManager(String vLogin, 482 AbstractConnectionManager connectionManager) 483 { 484 if (connectionManager == null) 485 throw new IllegalArgumentException (Translate.get( 486 "backend.null.connection.manager", new String []{name, url})); 487 if (logger.isInfoEnabled()) 488 logger.info(Translate.get("backend.add.connection.manager.for.user", 489 vLogin)); 490 connectionManager.setVLogin(vLogin); 491 connectionManager.setConnectionTestStatement(getConnectionTestStatement()); 492 connectionManagers.put(vLogin, connectionManager); 493 } 494 495 502 public void addDefaultConnectionManager(VirtualDatabaseUser vdbUser) 503 throws SQLException 504 { 505 if (defaultConnectionManager == null) 506 { 507 if (logger.isWarnEnabled()) 508 { 509 logger 510 .warn("Default connection manager undefined in backend configuration, setting to a VariablePoolConnectionManager"); 511 } 512 defaultConnectionManager = new VariablePoolConnectionManager(url, name, 513 vdbUser.getLogin(), vdbUser.getPassword(), driverPath, 514 driverClassName, 20, 5, 0, 180, 0); 515 } 516 AbstractConnectionManager connectionManager = defaultConnectionManager 517 .clone(vdbUser.getLogin(), vdbUser.getPassword()); 518 connectionManager.initializeConnections(); 519 addConnectionManager(vdbUser.getLogin(), connectionManager); 520 } 521 522 529 public void removeConnectionManager(VirtualDatabaseUser vdbUser) 530 throws SQLException 531 { 532 ((AbstractConnectionManager) connectionManagers.get(vdbUser)) 533 .finalizeConnections(); 534 connectionManagers.remove(vdbUser); 535 } 536 537 542 public void checkDriverCompliance() throws SQLException 543 { 544 if (connectionManagers.isEmpty()) 545 throw new SQLException (Translate.get("backend.null.connection.manager", 546 new String []{name, url})); 547 548 AbstractConnectionManager connectionManager; 549 Iterator iter = connectionManagers.values().iterator(); 550 connectionManager = (AbstractConnectionManager) iter.next(); 551 552 try 553 { 554 if (!driverCompliance.complianceTest(url, connectionManager.getLogin(), 555 connectionManager.getPassword(), connectionManager.getDriverPath(), 556 connectionManager.getDriverClassName(), connectionTestStatement)) 557 throw new SQLException (Translate.get("backend.driver.not.compliant", 558 driverClassName, ControllerConstants.PRODUCT_NAME)); 559 } 560 catch (ConnectException e) 561 { 562 throw (SQLException ) new SQLException (Translate.get( 563 "backend.cannot.connect.to", e)).initCause(e); 564 } 565 } 566 567 572 public void setDefaultConnectionManager( 573 AbstractConnectionManager defaultConnectionManager) 574 { 575 this.defaultConnectionManager = defaultConnectionManager; 576 } 577 578 584 public synchronized void initializeConnections() throws SQLException 585 { 586 if (connectionManagers.isEmpty()) 587 throw new SQLException (Translate.get("backend.not.defined", new String []{ 588 name, url})); 589 590 AbstractConnectionManager connectionManager; 591 Iterator iter = connectionManagers.values().iterator(); 592 while (iter.hasNext()) 593 { 594 connectionManager = (AbstractConnectionManager) iter.next(); 595 if (!connectionManager.isInitialized()) 596 connectionManager.initializeConnections(); 597 } 598 } 599 600 606 public synchronized void finalizeConnections() throws SQLException 607 { 608 612 synchronized (persistentConnections) 613 { 614 persistentConnections.clear(); 615 } 616 if (connectionManagers.isEmpty()) 617 throw new SQLException (Translate.get("backend.not.defined", new String []{ 618 name, url})); 619 620 AbstractConnectionManager connectionManager; 621 Iterator iter = connectionManagers.values().iterator(); 622 while (iter.hasNext()) 623 { 624 connectionManager = (AbstractConnectionManager) iter.next(); 625 if (connectionManager.isInitialized()) 626 connectionManager.finalizeConnections(); 627 } 628 } 629 630 634 public void flagAllConnectionsForRenewal() 635 { 636 AbstractConnectionManager connectionManager; 637 Iterator iter = connectionManagers.values().iterator(); 638 while (iter.hasNext()) 639 { 640 connectionManager = (AbstractConnectionManager) iter.next(); 641 if (connectionManager.isInitialized()) 642 connectionManager.flagAllConnectionsForRenewal(); 643 } 644 } 645 646 656 private final Object connectionMutex = new Object (); 657 658 664 public void addPersistentConnection(long persistentConnectionId, 665 PooledConnection c) 666 { 667 synchronized (persistentConnections) 668 { 669 persistentConnections.put(new Long (persistentConnectionId), c); 670 } 671 } 672 673 680 public boolean hasPersistentConnections() 681 { 682 return (persistentConnections.size() > 0); 683 } 684 685 690 public void removePersistentConnection(long persistentConnectionId) 691 { 692 synchronized (persistentConnections) 693 { 694 persistentConnections.remove(new Long (persistentConnectionId)); 695 if (persistentConnections.isEmpty()) 696 { 697 persistentConnections.notifyAll(); 698 } 699 } 700 } 701 702 720 public Connection getConnectionForTransactionAndLazyBeginIfNeeded( 721 AbstractRequest request, AbstractConnectionManager cm) 722 throws UnreachableBackendException, 723 NoTransactionStartWhenDisablingException, SQLException 724 { 725 Long tid = new Long (request.getTransactionId()); 726 732 if (isStartedTransaction(tid)) 733 { 734 PooledConnection pc = cm.retrieveConnectionForTransaction(request 735 .getTransactionId()); 736 if (pc != null) 737 { 738 return pc.getConnection(); 739 } 740 } 741 synchronized (connectionMutex) 742 { 743 748 if (isStartedTransaction(tid)) 749 { PooledConnection pc = cm.retrieveConnectionForTransaction(request 751 .getTransactionId()); 752 if ((pc == null) && isDisabling()) 753 { 754 762 Connection c = AbstractLoadBalancer.getConnectionAndBeginTransaction( 763 this, cm, request); 764 if (c == null) 765 { 766 if (logger.isWarnEnabled()) 767 { 768 logger 769 .warn("Null connection returned from AbstractLoadBalancer.getConnectionAndBeginTransaction() (backend is disabling)"); 770 } 771 } 772 return c; 773 } 774 if ((pc == null) && !isDisabling()) 775 { if (logger.isErrorEnabled()) 777 { 778 logger.error("Null connection [tid = " + request.getTransactionId() 779 + ", backend state = " + state + ", active tx = " 780 + activeTransactions + "]"); 781 } 782 return null; 783 } 784 return pc.getConnection(); 785 } 786 else 787 { 788 if (!canAcceptTasks(request)) 789 throw new NoTransactionStartWhenDisablingException(); 790 791 Connection c = null; 792 793 c = AbstractLoadBalancer.getConnectionAndBeginTransaction(this, cm, 795 request); 796 startTransaction(tid); 798 799 if (c == null) 800 { 801 if (logger.isWarnEnabled()) 802 { 803 logger 804 .warn("Null connection returned from AbstractLoadBalancer.getConnectionAndBeginTransaction() [state = " 805 + state + "]"); 806 } 807 } 808 return c; 809 } 810 } } 812 813 820 public AbstractConnectionManager getConnectionManager(String vLogin) 821 { 822 return (AbstractConnectionManager) connectionManagers.get(vLogin); 823 } 824 825 830 public String getConnectionTestStatement() 831 { 832 return connectionTestStatement; 833 } 834 835 843 public SQLWarning getPersistentConnectionWarnings(long connId) 844 throws SQLException 845 { 846 if (persistentConnections != null) 847 { 848 PooledConnection pc = (PooledConnection) persistentConnections 849 .get(new Long (connId)); 850 if (pc != null) 851 return pc.getConnection().getWarnings(); 852 } 853 return null; 854 } 855 856 862 public void clearPersistentConnectionWarnings(long connId) 863 throws SQLException 864 { 865 if (persistentConnections != null) 866 { 867 PooledConnection pc = (PooledConnection) persistentConnections 868 .get(new Long (connId)); 869 if (pc != null) 870 pc.getConnection().clearWarnings(); 871 } 872 } 873 874 883 public boolean isValidConnection(Connection connection) 884 { 885 try 886 { 887 Statement s = connection.createStatement(); 888 s.executeQuery(connectionTestStatement); 889 } 890 catch (SQLException e) 891 { 892 if ("25P02".equals(e.getSQLState()) 893 || (e.getMessage() != null && e.getMessage().indexOf( 894 "ignored until end of transaction block") > 0)) 895 { 896 return true; 907 } 908 return false; 909 } 910 return true; 911 } 912 913 916 public synchronized void shutdownConnectionManagers() 917 { 918 for (Iterator iter = connectionManagers.values().iterator(); iter.hasNext();) 919 { 920 AbstractConnectionManager cm = (AbstractConnectionManager) iter.next(); 921 if (cm.isInitialized()) 922 { 923 cm.shutdown(); 924 } 925 } 926 } 927 928 932 938 public void addSavepoint(Long tid, Savepoint savepoint) 939 { 940 synchronized (savepoints) 941 { 942 List savepointList = (List ) savepoints.get(tid); 943 if (savepointList == null) 944 { savepointList = new ArrayList (); 946 savepoints.put(tid, savepointList); 947 } 948 savepointList.add(savepoint); 949 } 950 } 951 952 962 public Savepoint getSavepoint(Long tid, String savepointName) 963 { 964 synchronized (savepoints) 965 { 966 List savepointList = (List ) savepoints.get(tid); 967 if (savepointList == null) 968 return null; 970 Iterator i = savepointList.iterator(); 971 while (i.hasNext()) 972 { 973 try 974 { 975 Savepoint savepoint = (Savepoint ) i.next(); 976 if (savepointName.equals(savepoint.getSavepointName())) 977 return savepoint; 978 } 979 catch (SQLException ignore) 980 { 981 } 984 } 985 } 986 987 return null; 989 } 990 991 998 public boolean isStartedTransaction(Long tid) 999 { 1000 synchronized (activeTransactions) 1001 { 1002 return activeTransactions.contains(tid); 1003 } 1004 } 1005 1006 1012 public void removeSavepoint(Long tid, Savepoint savepoint) 1013 { 1014 synchronized (savepoints) 1015 { 1016 List savepointList = (List ) savepoints.get(tid); 1017 if (savepointList == null) 1018 logger.error("No savepoints found for transaction " + tid); 1019 else 1020 savepointList.remove(savepoint); 1021 } 1022 } 1023 1024 1030 public void startTransaction(Long tid) 1031 { 1032 synchronized (activeTransactions) 1033 { 1034 totalTransactions++; 1035 activeTransactions.add(tid); 1036 } 1037 } 1038 1039 1045 public void stopTransaction(Long tid) 1046 { 1047 synchronized (activeTransactions) 1048 { 1049 if (!activeTransactions.remove(tid)) 1050 throw new IllegalArgumentException (Translate.get( 1051 "backend.transaction.not.started", new String []{"" + tid, name})); 1052 if (activeTransactions.isEmpty()) 1055 { 1056 activeTransactions.notifyAll(); 1057 } 1058 } 1059 1060 synchronized (savepoints) 1061 { 1062 savepoints.remove(tid); 1063 } 1064 } 1065 1066 1072 public void waitForAllTransactionsAndPersistentConnectionsToComplete() 1073 { 1074 synchronized (activeTransactions) 1076 { 1077 if (!activeTransactions.isEmpty()) 1078 { 1079 if (logger.isInfoEnabled()) 1080 logger.info("Backend " + name + " wait for " 1081 + activeTransactions.size() 1082 + " transactions to complete before disabling completely."); 1083 1084 try 1085 { 1086 activeTransactions.wait(); 1087 } 1088 catch (InterruptedException ignore) 1089 { 1090 } 1091 } 1092 } 1093 1094 synchronized (persistentConnections) 1096 { 1097 if (!persistentConnections.isEmpty()) 1098 { 1099 if (logger.isInfoEnabled()) 1100 logger 1101 .info("Backend " 1102 + name 1103 + " wait for " 1104 + persistentConnections.size() 1105 + " persistent connections to close before disabling completely."); 1106 1107 try 1108 { 1109 persistentConnections.wait(); 1110 } 1111 catch (InterruptedException ignore) 1112 { 1113 } 1114 } 1115 } 1116 } 1117 1118 1122 1131 public boolean canAcceptTasks(AbstractRequest request) 1132 { 1133 if (request != null) 1134 return canAcceptTasks(request.isPersistentConnection(), request 1135 .getPersistentConnectionId()); 1136 else 1137 return canAcceptTasks(false, -1); 1138 } 1139 1140 1149 public boolean canAcceptTasks(long persistentConnectionId) 1150 { 1151 return canAcceptTasks(true, persistentConnectionId); 1152 } 1153 1154 private boolean canAcceptTasks(boolean isPersistentConnection, 1155 long persistentConnectionId) 1156 { 1157 boolean acceptTask = state == BackendState.READ_ENABLED_WRITE_DISABLED 1159 || state == BackendState.READ_ENABLED_WRITE_ENABLED 1160 || state == BackendState.READ_DISABLED_WRITE_ENABLED 1161 || state == BackendState.REPLAYING; 1162 1163 if (!acceptTask && isPersistentConnection) 1164 { 1165 synchronized (persistentConnections) 1168 { 1169 return persistentConnections.containsKey(new Long ( 1170 persistentConnectionId)); 1171 } 1172 } 1173 return acceptTask; 1174 } 1175 1176 1179 private void cleanBackendStates() 1180 { 1181 activeTransactions.clear(); 1182 savepoints.clear(); 1183 pendingRequests.clear(); 1184 pendingTasks.clear(); 1185 setSchemaIsDirty(true, null); 1186 schema = null; 1188 } 1189 1190 1199 public synchronized boolean disable() 1200 { 1201 if (getStateValue() == BackendState.DISABLED) 1202 { 1203 return false; 1204 } 1205 setState(BackendState.DISABLED); 1206 1207 return true; 1208 } 1209 1210 1213 public synchronized void disableRead() 1214 { 1215 if (isWriteEnabled()) 1216 setState(BackendState.READ_DISABLED_WRITE_ENABLED); 1217 else 1218 setState(BackendState.DISABLED); 1219 } 1220 1221 1227 public synchronized void disableWrite() 1228 { 1229 if (isReadEnabled()) 1230 setState(BackendState.READ_ENABLED_WRITE_DISABLED); 1231 else 1232 setState(BackendState.DISABLED); 1233 } 1234 1235 1239 public synchronized void enableRead() 1240 { 1241 if (isWriteEnabled()) 1242 setState(BackendState.READ_ENABLED_WRITE_ENABLED); 1243 else 1244 setState(BackendState.READ_ENABLED_WRITE_DISABLED); 1245 } 1246 1247 1251 public synchronized void enableWrite() 1252 { 1253 setLastKnownCheckpoint(null); 1256 if (isReadEnabled()) 1257 setState(BackendState.READ_ENABLED_WRITE_ENABLED); 1258 else 1259 setState(BackendState.READ_DISABLED_WRITE_ENABLED); 1260 } 1261 1262 1267 public String getLastKnownCheckpoint() 1268 { 1269 return lastKnownCheckpoint; 1270 } 1271 1272 1283 public String getState() 1285 { 1286 switch (state) 1287 { 1288 case BackendState.READ_ENABLED_WRITE_DISABLED : 1289 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ENABLED; 1290 case BackendState.READ_ENABLED_WRITE_ENABLED : 1291 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ENABLED_WRITE; 1292 case BackendState.READ_DISABLED_WRITE_ENABLED : 1293 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_ENABLED_WRITE; 1294 case BackendState.DISABLING : 1295 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_DISABLING; 1296 case BackendState.BACKUPING : 1297 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_BACKINGUP; 1298 case BackendState.RESTORING : 1299 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_RECOVERING; 1300 case BackendState.REPLAYING : 1301 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_REPLAYING; 1302 case BackendState.DISABLED : 1303 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_DISABLED; 1304 case BackendState.UNKNOWN : 1305 return SequoiaNotificationList.VIRTUALDATABASE_BACKEND_UNKNOWN; 1306 default : 1307 throw new IllegalArgumentException ("Unknown backend state:" + state); 1308 } 1309 } 1310 1311 1318 public int getStateValue() 1319 { 1320 return state; 1321 } 1322 1323 1328 public boolean isBackuping() 1329 { 1330 return state == BackendState.BACKUPING; 1331 } 1332 1333 1339 public boolean isDisabled() 1340 { 1341 return state == BackendState.DISABLED; 1342 } 1343 1344 1349 public boolean isDisabling() 1350 { 1351 return state == BackendState.DISABLING; 1352 } 1353 1354 1360 public synchronized boolean isInitialized() throws SQLException 1361 { 1362 if (connectionManagers.isEmpty()) 1363 throw new SQLException (Translate.get("backend.null.connection.manager", 1364 new String []{name, url})); 1365 Iterator iter = connectionManagers.values().iterator(); 1366 while (iter.hasNext()) 1367 { 1368 if (!((AbstractConnectionManager) iter.next()).isInitialized()) 1369 return false; 1370 } 1371 return true; 1372 } 1373 1374 1380 public synchronized boolean isJDBCConnected() 1381 { 1382 Connection con = null; 1383 try 1384 { 1385 if (connectionManagers.isEmpty()) 1386 throw new SQLException (Translate.get("backend.null.connection.manager", 1387 new String []{name, url})); 1388 1389 AbstractConnectionManager connectionManager; 1390 Iterator iter = connectionManagers.values().iterator(); 1391 connectionManager = (AbstractConnectionManager) iter.next(); 1392 1393 con = connectionManager.getConnectionFromDriver(); 1394 if (con == null) 1395 { 1396 return false; 1397 } 1398 con.createStatement().execute(this.connectionTestStatement); 1399 return true; 1400 } 1401 catch (Exception e) 1402 { 1403 String msg = Translate.get("loadbalancer.backend.unreacheable", name); 1404 logger.warn(msg, e); 1405 return false; 1406 } 1407 finally 1408 { 1409 if (con != null) 1410 { 1411 try 1412 { 1413 con.close(); 1414 } 1415 catch (SQLException e) 1416 { 1417 return false; 1418 } 1419 } 1420 } 1421 } 1422 1423 1429 public boolean isKilled() 1431 { 1432 return state == BackendState.UNKNOWN; 1433 } 1434 1435 1440 public synchronized boolean isReadEnabled() 1441 { 1442 return state == BackendState.READ_ENABLED_WRITE_DISABLED 1443 || state == BackendState.READ_ENABLED_WRITE_ENABLED; 1444 } 1445 1446 1451 public boolean isRestoring() 1453 { 1454 return state == BackendState.RESTORING; 1455 } 1456 1457 1462 public boolean isReplaying() 1463 { 1464 return state == BackendState.REPLAYING; 1465 } 1466 1467 1472 public synchronized boolean isWriteEnabled() 1473 { 1474 return state == BackendState.READ_ENABLED_WRITE_ENABLED 1475 || state == BackendState.READ_DISABLED_WRITE_ENABLED; 1476 } 1477 1478 1483 public boolean isWriteCanBeEnabled() 1484 { 1485 return writeCanBeEnabled; 1486 } 1487 1488 1494 public void setNotificationBroadcaster( 1495 NotificationBroadcasterSupport notificationBroadcaster) 1496 { 1497 this.notificationBroadcaster = notificationBroadcaster; 1498 } 1499 1500 1513 private void notifyJMXStateChanged(String message, int oldState, 1514 int currentState) 1515 { 1516 try 1517 { 1518 Notification attrChangeNotification = new AttributeChangeNotification ( 1519 JmxConstants.getDatabaseBackendObjectName(vdb 1520 .getVirtualDatabaseName(), name), notificationSequence++, 1521 new Date ().getTime(), message, "StateValue", "Integer", new Integer (oldState), new Integer (currentState)); 1523 sendNotification(attrChangeNotification); 1524 } 1525 catch (MalformedObjectNameException e) 1526 { 1527 logger.warn("Unable to send JMX notification", e); 1528 } 1529 } 1530 1531 1537 public void notifyJmx(String type) 1538 { 1539 notifyJmx(type, SequoiaNotificationList.NOTIFICATION_LEVEL_INFO, Translate 1540 .get(type, getName())); 1541 } 1542 1543 1550 public void notifyJmxError(String type, Exception e) 1551 { 1552 notifyJmx(type, SequoiaNotificationList.NOTIFICATION_LEVEL_ERROR, Translate 1553 .get(type, new String []{getName(), e.getMessage()})); 1554 } 1555 1556 1563 private void notifyJmx(String type, String level, String message) 1564 { 1565 try 1566 { 1567 Notification notification = (new Notification (type, JmxConstants 1568 .getDatabaseBackendObjectName(vdb.getVirtualDatabaseName(), name), 1569 notificationSequence++, message)); 1570 1571 sendNotification(notification); 1572 } 1573 catch (MalformedObjectNameException e) 1574 { 1575 logger.warn("Unable to send JMX notification", e); 1576 } 1577 } 1578 1579 1584 private void sendNotification(Notification notification) 1585 { 1586 notificationBroadcaster.sendNotification(notification); 1587 } 1588 1589 1594 private void notifyStateListener() 1595 { 1596 if (stateListener != null) 1597 stateListener.stateChanged(this); 1598 } 1599 1600 1605 public void setStateListener(BackendStateListener stateListener) 1606 { 1607 this.stateListener = stateListener; 1608 } 1609 1610 1622 public void setDisabling() 1624 { 1625 setState(BackendState.DISABLING); 1626 } 1627 1628 1633 public void setLastKnownCheckpoint(String checkpoint) 1634 { 1635 this.lastKnownCheckpoint = checkpoint; 1636 notifyStateListener(); } 1638 1639 1645 public synchronized void setState(int state) 1648 { 1649 switch (state) 1650 { 1651 case BackendState.UNKNOWN : 1652 lastKnownCheckpoint = null; 1653 break; 1654 case BackendState.RESTORING : 1655 case BackendState.REPLAYING : 1656 cleanBackendStates(); 1657 break; 1658 case BackendState.READ_ENABLED_WRITE_DISABLED : 1659 case BackendState.READ_ENABLED_WRITE_ENABLED : 1660 case BackendState.READ_DISABLED_WRITE_ENABLED : 1661 case BackendState.DISABLING : 1662 case BackendState.BACKUPING : 1663 case BackendState.DISABLED : 1664 break; 1665 default : 1666 throw new IllegalArgumentException ("Unknown backend state:" + state); 1667 } 1668 int oldState = this.state; 1669 this.state = state; 1670 int currentState = this.state; 1671 if (logger.isDebugEnabled()) 1672 logger.debug(Translate.get("backend.state.changed", new String []{name, 1673 getState()})); 1674 endUserLogger.info(Translate.get("backend.state.changed", new String []{ 1675 name, BackendState.description(currentState)})); 1676 1677 notifyStateListener(); 1678 notifyJMXStateChanged(Translate.get(getState(), name), oldState, 1679 currentState); 1680 } 1681 1682 1686 1700 public synchronized boolean checkDatabaseSchema(Connection c) 1701 { 1702 if (logger.isDebugEnabled()) 1703 logger.debug(Translate.get("backend.dynamic.schema", 1704 DatabaseBackendSchemaConstants 1705 .fetchStoredProcedures(dynamicPrecision))); 1706 1707 boolean checked = true; 1708 if (c == null) 1709 { 1710 AbstractConnectionManager connectionMananger; 1711 Iterator iter = connectionManagers.values().iterator(); 1712 while (iter.hasNext()) 1713 { 1714 connectionMananger = (AbstractConnectionManager) iter.next(); 1715 1716 DatabaseBackendMetaData meta = new DatabaseBackendMetaData( 1718 connectionMananger, logger, vdb.getDynamicDatabaseSchema(), vdb 1719 .getVirtualDatabaseName()); 1720 1721 DatabaseSchema metaSchema; 1722 try 1723 { 1724 if (logger.isDebugEnabled()) 1725 logger.debug(Translate.get("backend.gathering.database.schema")); 1726 metaSchema = meta.getDatabaseSchema(); 1727 } 1728 catch (SQLException e) 1729 { 1730 if (logger.isWarnEnabled()) 1731 logger.warn(Translate.get("backend.gather.schema.failed", e)); 1732 return false; 1733 } 1734 if (schema == null) 1735 { 1736 if (logger.isDebugEnabled()) 1737 logger.debug(Translate.get("backend.use.gathered.schema.as.new")); 1738 schema = metaSchema; 1739 } 1740 else 1741 { 1742 if (logger.isInfoEnabled()) 1743 logger.info(Translate.get("backend.check.schema.compatibility")); 1744 if (schema.isCompatibleSubset(metaSchema)) 1745 logger.info(Translate.get("backend.schema.compatible.for.login", 1746 connectionMananger.getLogin())); 1747 else 1748 { 1749 checked = false; 1750 logger.warn(Translate.get( 1751 "backend.schema.not.compatible.for.login", connectionMananger 1752 .getLogin())); 1753 } 1754 } 1755 } 1756 } 1757 else 1758 { try 1760 { 1761 schema = new DatabaseSQLMetaData(logger, c, vdb 1762 .getDynamicDatabaseSchema()).createDatabaseSchema(vdb 1763 .getVirtualDatabaseName()); 1764 } 1765 catch (SQLException e) 1766 { 1767 if (logger.isInfoEnabled()) 1768 logger.info("Failed to fetch schema from given connection " + c, e); 1769 return checkDatabaseSchema(null); 1770 } 1771 } 1772 1773 setSchemaIsDirty(false, null); 1774 return checked; 1775 } 1776 1777 1784 public synchronized DatabaseSchema getDatabaseSchema() 1785 { 1786 if (schemaIsDirty) 1787 refreshSchema(null); 1788 return schema; 1789 } 1790 1791 1797 public MetadataContainer getDatabaseStaticMetadata() 1798 { 1799 AbstractConnectionManager connectionMananger; 1800 Iterator iter = connectionManagers.values().iterator(); 1801 if (iter.hasNext()) 1802 { 1803 connectionMananger = (AbstractConnectionManager) iter.next(); 1804 DatabaseBackendMetaData meta = new DatabaseBackendMetaData( 1806 connectionMananger, logger, vdb.getDynamicDatabaseSchema(), vdb 1807 .getVirtualDatabaseName()); 1808 try 1809 { 1810 return meta.retrieveDatabaseMetadata(); 1811 } 1812 catch (SQLException e) 1813 { 1814 return null; 1815 } 1816 } 1817 else 1818 return null; 1819 } 1820 1821 private static final Object DYNAMIC_PRECISION_SYNC = new Object (); 1822 1823 1830 public int getDynamicPrecision() 1831 { 1832 synchronized (DYNAMIC_PRECISION_SYNC) 1833 { 1834 if (dynamicPrecision != -1) return dynamicPrecision; 1836 1837 dynamicPrecision = DatabaseBackendSchemaConstants.FetchTables; 1839 DynamicDatabaseSchema dynamicSchema = vdb.getDynamicDatabaseSchema(); 1840 if (dynamicSchema.gatherSystemTables()) 1841 dynamicPrecision += DatabaseBackendSchemaConstants.FetchSystemTables; 1842 if (dynamicSchema.useStoredProcedures()) 1843 dynamicPrecision += DatabaseBackendSchemaConstants.FetchStoredProcedures; 1844 if (dynamicSchema.useViews()) 1845 dynamicPrecision += DatabaseBackendSchemaConstants.FetchViews; 1846 return dynamicPrecision; 1847 } 1848 } 1849 1850 1855 public String getSchemaName() 1856 { 1857 return vdb.getDynamicDatabaseSchema().getSchemaName(); 1858 } 1859 1860 1868 public Collection getTables() 1869 { 1870 DatabaseSchema schemaPtr = getDatabaseSchema(); 1871 if (schemaPtr == null) 1872 throw new NullPointerException (Translate.get("backend.schema.not.set")); 1873 return schemaPtr.getTables().values(); 1874 } 1875 1876 1885 public boolean hasTable(String table) 1886 { 1887 DatabaseSchema schemaPtr = getDatabaseSchema(); 1888 if (schemaPtr == null) 1889 throw new NullPointerException (Translate.get("backend.schema.not.set")); 1890 1891 return schemaPtr.hasTable(table); 1892 } 1893 1894 1904 public boolean hasTables(Collection tables) 1905 { 1906 DatabaseSchema schemaPtr = getDatabaseSchema(); 1907 if (schemaPtr == null) 1908 throw new NullPointerException (Translate.get("backend.schema.not.set")); 1909 1910 if (tables == null) 1911 throw new IllegalArgumentException (Translate.get("backend.null.tables")); 1912 1913 for (Iterator iter = tables.iterator(); iter.hasNext();) 1914 { 1915 if (!schemaPtr.hasTable((String ) iter.next())) 1916 return false; 1917 } 1918 return true; 1919 } 1920 1921 1931 public boolean hasStoredProcedure(String procedureName, int nbOfParameters) 1932 { 1933 DatabaseSchema schemaPtr = getDatabaseSchema(); 1934 if (schemaPtr == null) 1935 throw new NullPointerException (Translate.get("backend.schema.not.set")); 1936 1937 return schemaPtr.hasProcedure(procedureName, nbOfParameters); 1938 } 1939 1940 1946 public boolean isSchemaDirty() 1948 { 1949 return schemaIsDirty; 1950 } 1951 1952 1958 private synchronized void refreshSchema(Connection c) 1959 { 1960 DatabaseSchema oldSchema = schema; 1961 setDatabaseSchema(null); 1962 checkDatabaseSchema(c); if ((schema != null) && (oldSchema != null)) 1965 { 1966 schema.setLocks(oldSchema); 1967 } 1968 } 1969 1970 1976 public synchronized void setDatabaseSchema(DatabaseSchema databaseSchema) 1977 { 1978 schema = databaseSchema; 1979 } 1980 1981 1988 public void setSchemaIsDirty(boolean schemaIsDirty, AbstractRequest request) 1989 { 1990 if (request == null) 1991 { 1992 this.schemaIsDirty = schemaIsDirty; 1993 return; 1994 } 1995 1996 Connection c = null; 1999 PooledConnection pc = null; 2000 if (request.isPersistentConnection()) 2001 { 2002 AbstractConnectionManager cm = getConnectionManager(request.getLogin()); 2003 if (cm != null) 2004 try 2005 { 2006 pc = cm.retrieveConnectionInAutoCommit(request); 2007 if (pc != null) 2008 c = pc.getConnection(); 2009 } 2010 catch (UnreachableBackendException ignore) 2011 { 2012 } 2013 } 2014 else if (!request.isAutoCommit()) 2015 { 2016 AbstractConnectionManager cm = getConnectionManager(request.getLogin()); 2017 if (cm != null) 2018 pc = cm.retrieveConnectionForTransaction(request.getTransactionId()); 2019 if (pc != null) 2020 c = pc.getConnection(); 2021 } 2022 2023 if (c == null) 2024 this.schemaIsDirty = schemaIsDirty; 2025 else if (schemaIsDirty) 2026 refreshSchema(c); 2028 } 2029 2030 2037 public void setSchemaIsDirtyIfNeeded(StoredProcedure proc) 2038 { 2039 SemanticBehavior semantic = proc.getSemantic(); 2040 if ((semantic == null) || semantic.altersDatabaseSchema()) 2041 setSchemaIsDirty(true, proc); 2042 } 2043 2044 2064 public void updateDatabaseBackendSchema(AbstractWriteRequest request) 2065 { 2066 getDatabaseSchema().updateDatabaseSchema(request, logger, 2067 vdb.getRequestManager(), null, this); 2068 } 2069 2070 2074 2079 public void addRewritingRule(AbstractRewritingRule rule) 2080 { 2081 if (rewritingRules == null) 2082 rewritingRules = new ArrayList (); 2083 if (logger.isDebugEnabled()) 2084 logger.debug(Translate.get("backend.rewriting.rule.add", new String []{ 2085 rule.getQueryPattern(), rule.getRewrite()})); 2086 rewritingRules.add(rule); 2087 } 2088 2089 2095 public String rewriteQuery(String sqlQuery) 2096 { 2097 if (rewritingRules == null) 2098 return sqlQuery; 2099 int size = rewritingRules.size(); 2100 for (int i = 0; i < size; i++) 2101 { 2102 AbstractRewritingRule rule = (AbstractRewritingRule) rewritingRules 2103 .get(i); 2104 sqlQuery = rule.rewrite(sqlQuery); 2105 if (rule.hasMatched()) 2106 { if (logger.isDebugEnabled()) 2108 logger.debug(Translate.get("backend.rewriting.query", sqlQuery)); 2109 if (rule.isStopOnMatch()) 2110 break; } 2112 } 2113 return sqlQuery; 2114 } 2115 2116 2119 2120 2127 public void addPendingReadRequest(AbstractRequest request) 2128 { 2129 synchronized (pendingRequests) 2130 { 2131 totalRequest++; 2132 totalReadRequest++; 2133 pendingRequests.add(request); 2134 } 2135 } 2136 2137 2144 public void addPendingTask(AbstractTask task) 2145 { 2146 synchronized (pendingTasks) 2147 { 2148 totalTasks++; 2149 pendingTasks.add(task); 2150 } 2151 } 2152 2153 2160 public void addPendingWriteRequest(AbstractRequest request) 2161 { 2162 synchronized (pendingRequests) 2163 { 2164 totalRequest++; 2165 totalWriteRequest++; 2166 pendingRequests.add(request); 2167 } 2168 } 2169 2170 2173 public ArrayList getActiveTransactions() 2174 { 2175 return activeTransactions; 2176 } 2177 2178 2200 public String [] getBackendData() 2201 { 2202 String [] data = new String [14]; 2203 data[0] = this.name; 2204 data[1] = this.driverClassName; 2205 data[2] = this.url; 2206 data[3] = String.valueOf(this.activeTransactions.size()); 2207 data[4] = String.valueOf(this.pendingRequests.size()); 2208 data[5] = String.valueOf(this.isReadEnabled()); 2209 data[6] = String.valueOf(this.isWriteEnabled()); 2210 try 2211 { 2212 data[7] = String.valueOf(this.isInitialized()); 2213 } 2214 catch (Exception e) 2215 { 2216 data[7] = "unknown"; 2217 } 2218 2219 data[8] = String.valueOf(false); 2221 2222 data[9] = String.valueOf(this.connectionManagers.size()); 2223 data[10] = String.valueOf(getTotalActiveConnections()); 2224 data[11] = String.valueOf(totalRequest); 2225 data[12] = String.valueOf(totalTransactions); 2226 if (lastKnownCheckpoint == null || lastKnownCheckpoint.equalsIgnoreCase("")) 2227 data[13] = "<unknown>"; 2228 else 2229 data[13] = lastKnownCheckpoint; 2230 return data; 2231 } 2232 2233 2238 public BackendStatistics getBackendStats() 2239 { 2240 BackendStatistics stats = new BackendStatistics(); 2241 stats.setBackendName(name); 2242 stats.setDriverClassName(driverClassName); 2243 stats.setUrl(url); 2244 stats.setNumberOfActiveTransactions(activeTransactions.size()); 2245 stats.setNumberOfPendingRequests(pendingRequests.size()); 2246 stats.setNumberOfPersistentConnections(persistentConnections.size()); 2247 stats.setReadEnabled(isReadEnabled()); 2248 stats.setWriteEnabled(isWriteEnabled()); 2249 String initializationStatus = "<unknown>"; 2250 try 2251 { 2252 initializationStatus = String.valueOf(this.isInitialized()); 2253 } 2254 catch (Exception e) 2255 { 2256 } 2257 stats.setInitializationStatus(initializationStatus); 2258 stats.setNumberOfConnectionManagers(connectionManagers.size()); 2259 stats.setNumberOfTotalActiveConnections(getTotalActiveConnections()); 2260 stats.setNumberOfTotalRequests(totalRequest); 2261 stats.setNumberOfTotalTransactions(totalTransactions); 2262 if (lastKnownCheckpoint == null || lastKnownCheckpoint.equalsIgnoreCase("")) 2263 stats.setLastKnownCheckpoint("<unknown>"); 2264 else 2265 stats.setLastKnownCheckpoint(lastKnownCheckpoint); 2266 return stats; 2267 } 2268 2269 2275 public Vector getPendingRequests() 2276 { 2277 return pendingRequests; 2278 } 2279 2280 2290 public ArrayList getPendingRequestsDescription(int count, boolean fromFirst, 2291 boolean clone) 2292 { 2293 int size = pendingRequests.size(); 2294 int limit = (count == 0 || count > size) ? size : Math.min(size, count); 2295 ArrayList list = new ArrayList (limit); 2296 int start = (fromFirst) ? 0 : Math.min(limit - count, 0); 2297 if (!clone) 2298 { 2299 synchronized (pendingRequests) 2300 { 2301 for (int i = start; i < limit; i++) 2302 list.add(pendingRequests.get(i).toString()); 2303 } 2304 return list; 2305 } 2306 else 2307 { 2308 Vector cloneVector = (Vector ) pendingRequests.clone(); 2309 for (int i = start; i < limit; i++) 2310 list.add(cloneVector.get(i).toString()); 2311 return list; 2312 } 2313 } 2314 2315 2321 public long getTotalActiveConnections() 2322 { 2323 int activeConnections = 0; 2324 Iterator iter = connectionManagers.keySet().iterator(); 2325 while (iter.hasNext()) 2326 activeConnections += ((AbstractConnectionManager) connectionManagers 2327 .get(iter.next())).getCurrentNumberOfConnections(); 2328 return activeConnections; 2329 } 2330 2331 2336 public int getTotalTransactions() 2337 { 2338 return totalTransactions; 2339 } 2340 2341 2346 public int getTotalReadRequest() 2347 { 2348 return totalReadRequest; 2349 } 2350 2351 2356 public int getTotalWriteRequest() 2357 { 2358 return totalWriteRequest; 2359 } 2360 2361 2366 public int getTotalRequest() 2367 { 2368 return totalRequest; 2369 } 2370 2371 2378 public boolean removePendingRequest(AbstractRequest request) 2379 { 2380 return pendingRequests.remove(request); 2381 } 2382 2383 2390 public boolean removePendingTask(AbstractTask task) 2391 { 2392 return pendingTasks.remove(task); 2393 } 2394 2395 2399 2404 public String getDatabaseProductName() 2405 { 2406 return driverCompliance.getDatabaseProductName(); 2407 } 2408 2409 2412 public DriverCompliance getDriverCompliance() 2413 { 2414 return driverCompliance; 2415 } 2416 2417 2422 public String getDriverPath() 2423 { 2424 return driverPath; 2425 } 2426 2427 2432 public String getDriverClassName() 2433 { 2434 return driverClassName; 2435 } 2436 2437 2442 public String getName() 2443 { 2444 return name; 2445 } 2446 2447 2453 public int getSqlShortFormLength() 2454 { 2455 return sqlShortFormLength; 2456 } 2457 2458 2463 public String getURL() 2464 { 2465 return url; 2466 } 2467 2468 2473 public BackendTaskQueues getTaskQueues() 2474 { 2475 return taskQueues; 2476 } 2477 2478 2483 public void setTaskQueues(BackendTaskQueues taskQueues) 2484 { 2485 this.taskQueues = taskQueues; 2486 } 2487 2488 2493 public String getVirtualDatabaseName() 2494 { 2495 return vdb.getVirtualDatabaseName(); 2496 } 2497 2498 2502 2507 public synchronized String getXml() 2508 { 2509 String escapedUrl = url.replaceAll("&", "&"); 2512 2513 StringBuffer info = new StringBuffer (); 2514 info.append("<" + DatabasesXmlTags.ELT_DatabaseBackend + " " 2515 + DatabasesXmlTags.ATT_name + "=\"" + name + "\" " 2516 + DatabasesXmlTags.ATT_driver + "=\"" + driverClassName + "\" " 2517 + DatabasesXmlTags.ATT_url + "=\"" + escapedUrl + "\" " 2518 + DatabasesXmlTags.ATT_connectionTestStatement + "=\"" 2519 + connectionTestStatement + "\">"); 2520 2521 if (rewritingRules != null) 2522 { 2523 int size = rewritingRules.size(); 2524 for (int i = 0; i < size; i++) 2525 info.append(((AbstractRewritingRule) rewritingRules.get(i)).getXml()); 2526 } 2527 if (connectionManagers != null) 2528 { 2529 if (connectionManagers.isEmpty() == false) 2530 { 2531 AbstractConnectionManager connectionManager; 2532 Iterator iter = connectionManagers.values().iterator(); 2533 while (iter.hasNext()) 2534 { 2535 connectionManager = (AbstractConnectionManager) iter.next(); 2536 info.append(connectionManager.getXml()); 2537 } 2538 } 2539 } 2540 info.append("</" + DatabasesXmlTags.ELT_DatabaseBackend + ">"); 2541 return info.toString(); 2542 } 2543 2544 2549 public void setSqlShortFormLength(int sqlShortFormLength) 2550 { 2551 this.sqlShortFormLength = sqlShortFormLength; 2552 } 2553 2554 2559 public String toString() 2560 { 2561 return "Backend: Name[" + this.name + "] State[" + this.state 2562 + "] JDBCConnected[" + isJDBCConnected() + "] ActiveTransactions[" 2563 + activeTransactions.size() + "] PersistentConnections[" 2564 + persistentConnections + "] PendingRequests[" + pendingRequests.size() 2565 + "]"; 2566 } 2567 2568 2572 2578 public BackendWorkerThread getBackendWorkerThreadForNotification() 2579 { 2580 if ((workerThreads == null) || workerThreads.isEmpty()) 2581 return null; 2582 return (BackendWorkerThread) workerThreads.get(0); 2583 } 2584 2585 2590 public int getNbOfWorkerThreads() 2591 { 2592 return nbOfWorkerThreads; 2593 } 2594 2595 2600 public void setNbOfWorkerThreads(int nbOfWorkerThreads) 2602 { 2603 this.nbOfWorkerThreads = nbOfWorkerThreads; 2604 } 2605 2606 2612 public void startDeadlockDetectionThread(VirtualDatabase vdb) 2613 { 2614 taskQueues.startDeadlockDetectionThread(vdb); 2615 2616 } 2617 2618 2623 public void startWorkerThreads(AbstractLoadBalancer loadBalancer) 2624 { 2625 taskQueues.setAllowTasksToBePosted(true); 2626 synchronized (workerThreadSync) 2627 { 2628 if (logger.isDebugEnabled()) 2629 logger.debug(Translate.get( 2630 "loadbalancer.backend.workerthread.starting", new String []{ 2631 String.valueOf(nbOfWorkerThreads), name})); 2632 2633 if (workerThreads == null) 2634 workerThreads = new ArrayList (); 2635 for (int i = 0; i < nbOfWorkerThreads; i++) 2637 { 2638 BackendWorkerThread thread = new BackendWorkerThread(this, loadBalancer); 2639 workerThreads.add(thread); 2640 thread.setPlayCommitRollbackOnly(i == 0); 2642 thread.start(); 2643 } 2644 } 2645 } 2646 2647 2650 public void terminateWorkerThreads() 2651 { 2652 synchronized (workerThreadSync) 2653 { 2654 if (workerThreads == null) 2655 return; 2656 2657 int size = workerThreads.size(); 2659 2660 if (logger.isDebugEnabled()) 2661 logger.debug(Translate.get( 2662 "loadbalancer.backend.workerthread.stopping", new String []{ 2663 String.valueOf(size), name})); 2664 2665 for (int i = 0; i < size; i++) 2666 { 2667 KillThreadTask killBlockingThreadTask = new KillThreadTask(1, 1); 2668 taskQueues.addTaskToBackendTotalOrderQueue(killBlockingThreadTask); 2669 } 2670 2671 for (Iterator iter = workerThreads.iterator(); iter.hasNext();) 2673 { 2674 BackendWorkerThread thread = (BackendWorkerThread) iter.next(); 2675 if (thread != Thread.currentThread()) 2676 { try 2679 { 2680 thread.join(); 2681 } 2682 catch (InterruptedException ignore) 2683 { 2684 } 2685 } 2686 } 2687 2688 workerThreads.clear(); 2690 2691 taskQueues.abortRemainingRequests(); 2693 } 2694 } 2695 2696 2700 public void terminateDeadlockDetectionThread() 2701 { 2702 taskQueues.terminateDeadlockDetectionThread(); 2703 } 2704 2705 2724 public staticList toBackendInfos( 2725 List backends) 2726 { 2727 if (backends == null) 2728 { 2729 return new ArrayList (); 2730 } 2731 List backendInfos = new ArrayList (backends.size()); 2732 for (Iterator iter = backends.iterator(); iter.hasNext();) 2733 { 2734 DatabaseBackend backend = (DatabaseBackend) iter.next(); 2735 BackendInfo backendInfo = new BackendInfo(backend); 2736 backendInfo.setXml(null); 2740 backendInfos.add(backendInfo); 2741 } 2742 return backendInfos; 2743 } 2744 2745 2751 public boolean isValidBackendUser(VirtualDatabaseUser vdbUser) 2752 { 2753 Connection conn = null; 2754 try 2755 { 2756 conn = DriverManager.getConnection(url, vdbUser.getLogin(), vdbUser 2757 .getPassword(), driverPath, driverClassName); 2758 return true; 2759 } 2760 catch (SQLException ignore) 2761 { 2762 if (logger.isDebugEnabled()) 2763 { 2764 logger.debug("Failed to get connection using vdb user " 2765 + vdbUser.getLogin() + " as real user", ignore); 2766 } 2767 return false; 2768 } 2769 finally 2770 { 2771 if (conn != null) 2772 { 2773 try 2774 { 2775 conn.close(); 2776 } 2777 catch (SQLException ignore) 2778 { 2779 } 2781 } 2782 } 2783 } 2784 2785 2790 public Trace getLogger() 2791 { 2792 return logger; 2793 } 2794} | Popular Tags |