| 1 24 25 package org.objectweb.cjdbc.controller.requestmanager; 26 27 import java.sql.SQLException ; 28 import java.util.ArrayList ; 29 import java.util.Date ; 30 import java.util.Hashtable ; 31 import java.util.LinkedList ; 32 import java.util.Vector ; 33 34 import javax.management.NotCompliantMBeanException ; 35 36 import org.objectweb.cjdbc.common.exceptions.BackupException; 37 import org.objectweb.cjdbc.common.exceptions.NoMoreBackendException; 38 import org.objectweb.cjdbc.common.exceptions.RollbackException; 39 import org.objectweb.cjdbc.common.i18n.Translate; 40 import org.objectweb.cjdbc.common.jmx.JmxConstants; 41 import org.objectweb.cjdbc.common.jmx.mbeans.RequestManagerMBean; 42 import org.objectweb.cjdbc.common.jmx.notifications.CjdbcNotificationList; 43 import org.objectweb.cjdbc.common.log.Trace; 44 import org.objectweb.cjdbc.common.shared.BackendState; 45 import org.objectweb.cjdbc.common.shared.DumpInfo; 46 import org.objectweb.cjdbc.common.sql.AbstractWriteRequest; 47 import org.objectweb.cjdbc.common.sql.AlterRequest; 48 import org.objectweb.cjdbc.common.sql.CreateRequest; 49 import org.objectweb.cjdbc.common.sql.ParsingGranularities; 50 import org.objectweb.cjdbc.common.sql.RequestType; 51 import org.objectweb.cjdbc.common.sql.SelectRequest; 52 import org.objectweb.cjdbc.common.sql.StoredProcedure; 53 import org.objectweb.cjdbc.common.sql.UpdateRequest; 54 import org.objectweb.cjdbc.common.sql.schema.DatabaseSchema; 55 import org.objectweb.cjdbc.common.sql.schema.DatabaseTable; 56 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 57 import org.objectweb.cjdbc.common.xml.XmlComponent; 58 import org.objectweb.cjdbc.controller.backend.BackendStateListener; 59 import org.objectweb.cjdbc.controller.backend.DatabaseBackend; 60 import org.objectweb.cjdbc.controller.backup.BackupManager; 61 import org.objectweb.cjdbc.controller.backup.Backuper; 62 import org.objectweb.cjdbc.controller.cache.metadata.MetadataCache; 63 import org.objectweb.cjdbc.controller.cache.parsing.ParsingCache; 64 import org.objectweb.cjdbc.controller.cache.result.AbstractResultCache; 65 import org.objectweb.cjdbc.controller.cache.result.entries.AbstractResultCacheEntry; 66 import org.objectweb.cjdbc.controller.jmx.AbstractStandardMBean; 67 import org.objectweb.cjdbc.controller.jmx.MBeanServerManager; 68 import org.objectweb.cjdbc.controller.loadbalancer.AbstractLoadBalancer; 69 import org.objectweb.cjdbc.controller.loadbalancer.AllBackendsFailedException; 70 import org.objectweb.cjdbc.controller.recoverylog.BackendRecoveryInfo; 71 import org.objectweb.cjdbc.controller.recoverylog.RecoverThread; 72 import org.objectweb.cjdbc.controller.recoverylog.RecoveryLog; 73 import org.objectweb.cjdbc.controller.scheduler.AbstractScheduler; 74 import org.objectweb.cjdbc.controller.virtualdatabase.ControllerResultSet; 75 import org.objectweb.cjdbc.controller.virtualdatabase.VirtualDatabase; 76 77 91 public class RequestManager extends AbstractStandardMBean 92 implements 93 XmlComponent, 94 RequestManagerMBean 95 { 96 97 108 109 protected long beginTimeout; 110 111 112 protected long commitTimeout; 113 114 115 protected long rollbackTimeout; 116 117 118 protected VirtualDatabase vdb; 119 120 121 protected AbstractScheduler scheduler; 122 123 124 protected AbstractResultCache resultCache; 125 126 127 protected AbstractLoadBalancer loadBalancer; 128 129 130 protected RecoveryLog recoveryLog; 131 132 133 protected BackupManager backupManager; 134 135 protected DatabaseSchema dbs; 137 138 139 private boolean schemaIsDirty = false; 140 141 private boolean schemaIsStatic = false; 142 143 private boolean isCaseSensitiveParsing = false; 144 145 protected ParsingCache parsingCache = null; 146 147 private MetadataCache metadataCache = null; 148 149 protected int schedulerParsingranularity = ParsingGranularities.NO_PARSING; 152 153 private int cacheParsingranularity = ParsingGranularities.NO_PARSING; 154 155 private int loadBalancerParsingranularity = ParsingGranularities.NO_PARSING; 156 157 protected int requiredParsingGranularity = ParsingGranularities.NO_PARSING; 158 159 160 protected Hashtable tidLoginTable; 161 162 163 protected Hashtable tidSavepoints; 164 165 protected static Trace logger = null; 166 167 private BackendStateListener backendStateListener; 168 169 173 187 public RequestManager(VirtualDatabase vdb, AbstractScheduler scheduler, 188 AbstractResultCache cache, AbstractLoadBalancer loadBalancer, 189 RecoveryLog recoveryLog, long beginTimeout, long commitTimeout, 190 long rollbackTimeout) throws SQLException , NotCompliantMBeanException  191 { 192 super(RequestManagerMBean.class); 193 this.vdb = vdb; 194 assignAndCheckSchedulerLoadBalancerValidity(scheduler, loadBalancer); 195 this.resultCache = cache; 197 if (resultCache != null) 198 { 199 cacheParsingranularity = cache.getParsingGranularity(); 200 if (cacheParsingranularity > requiredParsingGranularity) 201 requiredParsingGranularity = cacheParsingranularity; 202 } 203 setRecoveryLog(recoveryLog); 204 initRequestManagerVariables(vdb, beginTimeout, commitTimeout, 205 rollbackTimeout); 206 setBackendsLastKnownCheckpointFromRecoveryLog(); 207 logger.info(Translate.get("requestmanager.parsing.granularity", 208 ParsingGranularities.getInformation(requiredParsingGranularity))); 209 210 if (MBeanServerManager.isJmxEnabled()) 211 { 212 try 213 { 214 MBeanServerManager.registerMBean(this, JmxConstants 215 .getRequestManagerObjectName(vdb.getVirtualDatabaseName())); 216 217 } 218 catch (Exception e) 219 { 220 logger.error(Translate.get("jmx.failed.register.mbean.requestmanager")); 221 } 222 } 223 } 224 225 229 private void setBackendsLastKnownCheckpointFromRecoveryLog() 230 { 231 232 if (recoveryLog == null) 233 return; 234 String databaseName = vdb.getVirtualDatabaseName(); 235 ArrayList backends = vdb.getBackends(); 236 int size = backends.size(); 237 DatabaseBackend backend; 238 BackendRecoveryInfo info; 239 for (int i = 0; i < size; i++) 240 { 241 backend = (DatabaseBackend) backends.get(i); 242 info = recoveryLog 243 .getBackendRecoveryInfo(databaseName, backend.getName()); 244 backend.setLastKnownCheckpoint(info.getCheckpoint()); 245 } 246 247 } 248 249 257 private void assignAndCheckSchedulerLoadBalancerValidity( 258 AbstractScheduler scheduler, AbstractLoadBalancer loadBalancer) 259 throws SQLException  260 { 261 if (scheduler == null) 262 throw new SQLException (Translate.get("requestmanager.null.scheduler")); 263 264 if (loadBalancer == null) 265 throw new SQLException (Translate.get("requestmanager.null.loadbalancer")); 266 267 if (scheduler.getRAIDbLevel() != loadBalancer.getRAIDbLevel()) 268 throw new SQLException (Translate.get( 269 "requestmanager.incompatible.raidb.levels", 270 new String []{"" + scheduler.getRAIDbLevel(), 271 "" + loadBalancer.getRAIDbLevel()})); 272 273 setScheduler(scheduler); 275 schedulerParsingranularity = scheduler.getParsingGranularity(); 276 requiredParsingGranularity = schedulerParsingranularity; 277 setLoadBalancer(loadBalancer); 278 loadBalancerParsingranularity = loadBalancer.getParsingGranularity(); 279 if (loadBalancerParsingranularity > requiredParsingGranularity) 280 requiredParsingGranularity = loadBalancerParsingranularity; 281 } 282 283 291 private void initRequestManagerVariables(VirtualDatabase vdb, 292 long beginTimeout, long commitTimeout, long rollbackTimeout) 293 { 294 this.tidLoginTable = new Hashtable (); 295 this.tidSavepoints = new Hashtable (); 296 this.beginTimeout = beginTimeout; 297 this.commitTimeout = commitTimeout; 298 this.rollbackTimeout = rollbackTimeout; 299 this.vdb = vdb; 300 logger = Trace.getLogger("org.objectweb.cjdbc.controller.RequestManager." 301 + vdb.getDatabaseName()); 302 } 303 304 308 316 public ControllerResultSet execReadRequest(SelectRequest request) 317 throws SQLException  318 { 319 if (!request.isAutoCommit()) 321 { long tid = request.getTransactionId(); 324 if (!tidLoginTable.containsKey(new Long (tid))) 325 throw new SQLException (Translate.get("transaction.not.started", tid)); 326 } 327 328 if ((requiredParsingGranularity != ParsingGranularities.NO_PARSING) 334 && (!request.isParsed())) 335 { 336 if (parsingCache == null) 337 request.parse(getDatabaseSchema(), requiredParsingGranularity, 338 isCaseSensitiveParsing); 339 else 340 parsingCache.getParsingFromCache(request); 341 } 342 343 347 if ((schedulerParsingranularity != ParsingGranularities.NO_PARSING) 351 && !request.isParsed()) 352 { 353 if (parsingCache == null) 354 request.parse(dbs, requiredParsingGranularity, isCaseSensitiveParsing); 355 else 356 parsingCache.getParsingFromCacheAndParseIfMissing(request); 357 } 358 359 if (logger.isDebugEnabled()) 360 logger.debug(Translate.get("requestmanager.read.request.schedule", 361 new String []{String.valueOf(request.getId()), 362 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 363 364 scheduler.scheduleReadRequest(request); 366 367 371 ControllerResultSet result = null; 372 try 373 { if (resultCache != null) 375 { 376 if (logger.isDebugEnabled()) 377 logger.debug(Translate.get("requestmanager.read.request.cache.get", 378 new String []{String.valueOf(request.getId()), 379 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 380 381 AbstractResultCacheEntry qce = resultCache.getFromCache(request, true); 382 if (qce != null) 383 { 384 result = qce.getResult(); 385 if (result != null) 386 { if (vdb.getSQLMonitor() != null) 388 vdb.getSQLMonitor().logCacheHit(request); 389 390 scheduler.readCompleted(request); 391 return result; 392 } 393 } 394 } 395 396 400 if (logger.isDebugEnabled()) 401 logger.debug(Translate.get("requestmanager.read.request.balance", 402 new String []{String.valueOf(request.getId()), 403 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 404 405 if ((loadBalancerParsingranularity != ParsingGranularities.NO_PARSING) 410 && !request.isParsed()) 411 { 412 if (parsingCache == null) 413 request 414 .parse(dbs, requiredParsingGranularity, isCaseSensitiveParsing); 415 else 416 parsingCache.getParsingFromCacheAndParseIfMissing(request); 417 } 418 419 result = loadBalancer.execReadRequest(request, metadataCache); 421 422 426 if ((resultCache != null) 428 && (request.getCacheAbility() != RequestType.UNCACHEABLE)) 429 { 430 if (logger.isDebugEnabled()) 431 logger.debug(Translate.get( 432 "requestmanager.read.request.cache.update", new String []{ 433 String.valueOf(request.getId()), 434 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 435 436 if (!request.isParsed() 437 && (cacheParsingranularity != ParsingGranularities.NO_PARSING)) 438 { if (parsingCache == null) 441 request.parse(dbs, requiredParsingGranularity, 442 isCaseSensitiveParsing); 443 else 444 parsingCache.getParsingFromCacheAndParseIfMissing(request); 445 } 446 resultCache.addToCache(request, result); 447 } 448 } 449 catch (Exception failed) 450 { 451 if (resultCache != null) 452 resultCache.removeFromPendingQueries(request); 453 scheduler.readCompleted(request); 454 if (failed instanceof NoMoreBackendException) 455 throw (NoMoreBackendException) failed; 456 String msg = Translate.get("requestmanager.request.failed", new String []{ 457 request.getSQLShortForm(vdb.getSQLShortFormLength()), 458 failed.getMessage()}); 459 if (failed instanceof RuntimeException ) 460 logger.warn(msg, failed); 461 else 462 logger.warn(msg); 463 if (failed instanceof SQLException ) 464 throw (SQLException ) failed; 465 466 throw new SQLException (msg); 467 } 468 469 scheduler.readCompleted(request); 471 472 return result; 473 } 474 475 484 public int execWriteRequest(AbstractWriteRequest request) throws SQLException  485 { 486 scheduleExecWriteRequest(request); 487 int execWriteRequestResult = 0; 488 try 489 { 490 execWriteRequestResult = loadBalanceExecWriteRequest(request); 491 } 492 catch (AllBackendsFailedException e) 493 { 494 String msg = Translate 495 .get("requestmanager.write.request.failed.unexpected"); 496 logger.fatal(msg, e); 497 throw new RuntimeException (msg, e); 498 } 499 updateAndNotifyExecWriteRequest(request); 500 return execWriteRequestResult; 501 } 502 503 512 public ControllerResultSet execWriteRequestWithKeys( 513 AbstractWriteRequest request) throws SQLException  514 { 515 scheduleExecWriteRequest(request); 516 ControllerResultSet execWriteRequestWithKeysResult = null; 517 try 518 { 519 execWriteRequestWithKeysResult = loadBalanceExecWriteRequestWithKeys(request); 520 } 521 catch (AllBackendsFailedException e) 522 { 523 String msg = Translate 524 .get("requestmanager.write.request.keys.failed.unexpected"); 525 logger.fatal(msg, e); 526 throw new RuntimeException (msg, e); 527 } 528 updateAndNotifyExecWriteRequest(request); 529 return execWriteRequestWithKeysResult; 530 } 531 532 538 public void scheduleExecWriteRequest(AbstractWriteRequest request) 539 throws SQLException  540 { 541 if (!request.isAutoCommit()) 543 { long tid = request.getTransactionId(); 546 if (!tidLoginTable.containsKey(new Long (tid))) 547 throw new SQLException (Translate.get("transaction.not.started", tid)); 548 } 549 550 if ((requiredParsingGranularity != ParsingGranularities.NO_PARSING) 556 && (!request.isParsed())) 557 { 558 if (parsingCache == null) 559 request.parse(getDatabaseSchema(), requiredParsingGranularity, 560 isCaseSensitiveParsing); 561 else 562 parsingCache.getParsingFromCache(request); 563 } 564 565 569 if ((schedulerParsingranularity != ParsingGranularities.NO_PARSING) 573 && !request.isParsed()) 574 { 575 if (parsingCache == null) 576 request.parse(getDatabaseSchema(), requiredParsingGranularity, 577 isCaseSensitiveParsing); 578 else 579 parsingCache.getParsingFromCacheAndParseIfMissing(request); 580 } 581 582 if (logger.isDebugEnabled()) 583 logger.debug(Translate.get("requestmanager.write.request.schedule", 584 new String []{String.valueOf(request.getId()), 585 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 586 587 try 589 { 590 scheduler.scheduleWriteRequest(request); 591 } 592 catch (RollbackException e) 593 { rollback(request.getTransactionId(), true); 595 throw new SQLException (e.getMessage()); 596 } 597 598 try 604 { 605 if ((requiredParsingGranularity != ParsingGranularities.NO_PARSING) 606 && !request.isParsed()) 607 { 608 if (parsingCache == null) 609 request.parse(getDatabaseSchema(), requiredParsingGranularity, 610 isCaseSensitiveParsing); 611 else 612 parsingCache.getParsingFromCacheAndParseIfMissing(request); 613 } 614 } 615 catch (SQLException e) 616 { 617 scheduler.writeCompleted(request); 619 throw e; 620 } 621 } 622 623 633 public ControllerResultSet loadBalanceExecWriteRequestWithKeys( 634 AbstractWriteRequest request) throws AllBackendsFailedException, 635 SQLException  636 { 637 if (logger.isDebugEnabled()) 638 logger.debug(Translate.get("requestmanager.write.request.balance", 639 new String []{String.valueOf(request.getId()), 640 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 641 642 try 643 { return loadBalancer.execWriteRequestWithKeys(request, metadataCache); 645 } 646 catch (Exception failed) 647 { 648 scheduler.writeCompleted(request); 649 String msg = Translate.get("requestmanager.request.failed", new String []{ 650 request.getSQLShortForm(vdb.getSQLShortFormLength()), 651 failed.getMessage()}); 652 if (failed instanceof RuntimeException ) 653 logger.warn(msg, failed); 654 else 655 logger.warn(msg); 656 if (failed instanceof AllBackendsFailedException) 657 throw (AllBackendsFailedException) failed; 658 else 659 throw new SQLException (msg); 660 } 661 } 662 663 673 public int loadBalanceExecWriteRequest(AbstractWriteRequest request) 674 throws AllBackendsFailedException, SQLException  675 { 676 if (logger.isDebugEnabled()) 677 logger.debug(Translate.get("requestmanager.write.request.balance", 678 new String []{String.valueOf(request.getId()), 679 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 680 681 try 682 { if (request.isUpdate() && (resultCache != null)) 684 { if (!resultCache.isUpdateNecessary((UpdateRequest) request)) 687 return 0; 688 } 689 return loadBalancer.execWriteRequest(request); 690 } 691 catch (Exception failed) 692 { 693 scheduler.writeCompleted(request); 694 String msg = Translate.get("requestmanager.request.failed", new String []{ 695 request.getSQLShortForm(vdb.getSQLShortFormLength()), 696 failed.getMessage()}); 697 698 if (failed instanceof RuntimeException ) 700 logger.warn(msg, failed); 701 else 702 logger.warn(msg); 703 704 if (failed instanceof AllBackendsFailedException) 706 throw (AllBackendsFailedException) failed; 707 else if (failed instanceof SQLException ) 708 throw (SQLException ) failed; 709 else 710 throw new SQLException (msg); 711 } 712 } 713 714 722 public void updateAndNotifyExecWriteRequest(AbstractWriteRequest request) 723 throws SQLException  724 { 725 try 726 { if (resultCache != null) 728 { if (logger.isDebugEnabled()) 730 logger.debug(Translate.get( 731 "requestmanager.write.request.cache.update", new String []{ 732 String.valueOf(request.getId()), 733 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 734 735 resultCache.writeNotify(request); 736 } 737 738 if (metadataCache != null) 739 { 740 if (request.isAlter() || request.isDrop()) 741 metadataCache.flushCache(); 744 } 745 746 if (recoveryLog != null) 748 { 749 if (logger.isDebugEnabled()) 750 logger.debug(Translate.get("requestmanager.write.request.log", 751 new String []{String.valueOf(request.getId()), 752 request.getSQLShortForm(vdb.getSQLShortFormLength())})); 753 754 recoveryLog.logRequest(request); 755 } 756 757 if ((request.isDDL()) 759 && (requiredParsingGranularity != ParsingGranularities.NO_PARSING)) 760 { 761 if (request.isCreate()) 762 { CreateRequest createRequest = (CreateRequest) request; 764 if (createRequest.altersDatabaseSchema()) 765 { 766 if (createRequest.getDatabaseTable() != null) 767 { 768 getDatabaseSchema().addTable( 769 ((CreateRequest) request).getDatabaseTable()); 770 if (logger.isDebugEnabled()) 771 logger.debug(Translate.get("requestmanager.schema.add.table", 772 request.getTableName())); 773 } 774 else 775 schemaIsDirty = true; 778 } 779 } 780 else if (request.isDrop()) 781 { if (getDatabaseSchema().removeTable( 783 getDatabaseSchema().getTable(request.getTableName()))) 784 if (logger.isDebugEnabled()) 785 logger.debug(Translate.get("requestmanager.schema.remove.table", 786 request.getTableName())); 787 else 788 schemaIsDirty = true; 790 } 791 else if (request.isAlter() 792 && (requiredParsingGranularity > ParsingGranularities.TABLE)) 793 { AlterRequest req = (AlterRequest) request; 795 DatabaseTable alteredTable = getDatabaseSchema().getTable( 796 req.getTableName()); 797 if ((alteredTable != null) && (req.getColumn() != null)) 798 { 799 if (req.isDrop()) 800 alteredTable.remove(req.getColumn().getName()); 801 else if (req.isAdd()) 802 alteredTable.addColumn(req.getColumn()); 803 else 804 schemaIsDirty = true; 806 } 807 else 808 schemaIsDirty = true; 810 } 811 else 812 schemaIsDirty = true; 814 } 815 } 816 catch (Exception failed) 817 { 818 scheduler.writeCompleted(request); 819 String msg = Translate.get("requestmanager.request.failed", new String []{ 820 request.getSQLShortForm(vdb.getSQLShortFormLength()), 821 failed.getMessage()}); 822 if (failed instanceof RuntimeException ) 823 logger.warn(msg, failed); 824 else 825 logger.warn(msg); 826 throw new SQLException (msg); 827 } 828 finally 829 { 830 scheduler.writeCompleted(request); 832 } 833 } 834 835 844 public ControllerResultSet execReadStoredProcedure(StoredProcedure proc) 845 throws AllBackendsFailedException, SQLException  846 { 847 ControllerResultSet result = null; 848 try 849 { 850 scheduleStoredProcedure(proc); 851 852 if (logger.isDebugEnabled()) 853 logger.debug(Translate.get("requestmanager.read.stored.procedure", 854 new String []{String.valueOf(proc.getId()), 855 proc.getSQLShortForm(vdb.getSQLShortFormLength())})); 856 857 result = loadBalanceReadStoredProcedure(proc); 858 859 flushCacheAndLogStoredProcedure(proc, true); 860 861 scheduler.storedProcedureCompleted(proc); 863 864 return result; 865 } 866 catch (AllBackendsFailedException e) 867 { 868 throw e; 869 } 870 catch (Exception failed) 871 { 872 scheduler.storedProcedureCompleted(proc); 873 String msg = Translate.get("requestmanager.stored.procedure.failed", 874 new String []{proc.getSQLShortForm(vdb.getSQLShortFormLength()), 875 failed.getMessage()}); 876 logger.warn(msg); 877 if (failed instanceof SQLException ) 878 { 879 throw (SQLException ) failed; 880 } 881 throw new SQLException (msg); 882 } 883 } 884 885 |