1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * ident "%Z%%M% %I% %E% SMI" 27 */ 28 29 package com.sun.solaris.domain.pools; 30 31 import java.io.*; 32 import java.util.*; 33 import java.util.logging.*; 34 import java.text.DecimalFormat; 35 import java.util.concurrent.atomic.*; 36 37 import com.sun.solaris.service.locality.*; 38 import com.sun.solaris.service.logging.*; 39 import com.sun.solaris.service.pools.*; 40 import com.sun.solaris.service.exception.*; 41 42 /* 43 * poold overview 44 * ----- -------- 45 * 46 * poold manipulates system resources in accordance with administrator 47 * specified constraints and objectives. The "goal" of the application 48 * is to maximise the efficiency of available resources within these 49 * parameters. 50 * 51 * Constraints are specified as follows: 52 * 53 * On a resource set: 54 * 55 * - min Is the minimum amount of resource a set should 56 * receive. poold will never elect to move resource so that a set 57 * falls below its minimum value. It is possible for a set to 58 * fall below its minimum as a consequence of administrative 59 * intervention, in which case poold will endeavour to bring a 60 * set back to its minimum level at the earliest opportunity. 61 * 62 * - max Is the maximum amount of resource a set should 63 * recieve. poold will never elect to move resource so that a set 64 * rises above its maximum value. It is possible for a set to 65 * rise above its maximum as a consequence of administrative 66 * intervention, in which case poold will endeavour to bring a 67 * set back to its maximum level at the earliest opportunity. 68 * 69 * On a resource component: 70 * 71 * - cpu.pinned Is an indication that a CPU should be ignored by 72 * poold for purposes of reallocation. A pinned CPU will never be 73 * moved by poold from one set to another. 74 * 75 * In addition to constraints, an administrator may also specify 76 * objectives. Currently three types of objectives are supported: 77 * 78 * - system.wt-load Is an objective set across an entire 79 * configuration. It attempts to ensure that resource is shared 80 * in accordance with current consumption. Those partitions which 81 * are most heavily utilized are give more resource in an attempt 82 * to lower their utilization levels. 83 * 84 * - set.locality Is a locality objective which attempts to 85 * minimize or maximize resource locality for a set. 86 * 87 * - set.utilization Is a utilization based objective which an 88 * administrator may use to explicitly dictate the utilization 89 * levels which should be achieved for a set. 90 * 91 * When executing, poold uses information about the current pools 92 * configuration; monitored resource utilization and specified 93 * constraints and objectives to determine if a move of resources is 94 * likely to lead to an increase in objective satisfaction. 95 * 96 * Candidate moves are generated by observing resource constraints. 97 * These moves are evaluated and scored in terms of their contribution 98 * to objective satisfaction (note: objectives are weighted according 99 * to their importance) and ranked accordingly. If a move can be 100 * identified that delivers an improvement, the move is made. Data is 101 * collected about past moves and recorded as "Decision History", 102 * before the move is made this data is consulted and if the move is 103 * expected not to yield an improvement, it may be cancelled. This 104 * refinement is designed to improve the quality of decision making by 105 * reflecting upon the past performance of decisions as well as the 106 * contribution to objective satisfaction. 107 * 108 * poold structure 109 * ----- --------- 110 * 111 * The common package name begins with: 112 * 113 * com.sun.solaris 114 * 115 * The software is divided into two main functional areas: 116 * 117 * service 118 * 119 * These packages collaborate to provide services to poold 120 * (typically, they use JNI to access exising 121 * functionality). They are not designed to be extended. For more 122 * details on these classes examine the source files in each 123 * directory. 124 * 125 * exception Stack trace formatter 126 * kstat Interface to Solaris kstat facility 127 * locality Interface to Solaris lgrp facility 128 * logging Interface to Solaris syslog facility 129 * pools Interface to Solaris libpool facility 130 * timer High resolution timestamps 131 * 132 * domain: 133 * 134 * These package reflect problem domain concepts and are 135 * responsible for application logic related to these 136 * concepts. 137 * 138 * pools Dynamic Resource Pools specific functionality. 139 * 140 * This code block will continue to explain in more detail how poold 141 * is organized. 142 * 143 * poold provides the following basic facilities: 144 * 145 * Monitoring: 146 * 147 * Basic statistic access is provided by the 148 * com.sun.solaris.service.kstat package. The following interfaces and 149 * classes collaborate to provide higher level statistic and 150 * monitoring facilities to the application: 151 * 152 * INTERFACES 153 * 154 * AggregateStatistic 155 * Monitor 156 * Statistic 157 * StatisticListener 158 * 159 * CLASSES 160 * 161 * AbstractStatistic 162 * DoubleStatistic 163 * LongStatistic 164 * ResourceMonitor 165 * StatisticEvent 166 * StatisticList 167 * StatisticOperations 168 * SystemMonitor 169 * UnsignedInt64Statistic 170 * 171 * Logging: 172 * 173 * Logging services are provided by the com.sun.solaris.logging 174 * package. In addition, the following class implements Poold's 175 * specific logging requirements. 176 * 177 * CLASSES 178 * 179 * Poold 180 * 181 * Optimization: 182 * 183 * lgrp service are provided by the com.sun.solaris.service.lgrp 184 * package. pools services are provided by the 185 * com.sun.solaris.service.pools package. In addition, optimization is 186 * implemented in the following Interfaces and Classes: 187 * 188 * INTERFACES 189 * 190 * Objective 191 * Solver 192 * WorkloadDependentObjective 193 * 194 * CLASSES 195 * 196 * AbstractObjective 197 * ComponentMove 198 * DecisionHistory 199 * Expression 200 * KExpression 201 * KVEpression 202 * KVOpExpression 203 * LocalityObjective 204 * Move 205 * Poold 206 * QuantityMove 207 * SystemSolver 208 * UtilizationObjective 209 * WeightedLoadObjective 210 * 211 * Configuration: 212 * 213 * pools services are provided by the com.sun.solaris.service.pools 214 * package, this is used to read poold configuration details from a 215 * libpool configuration. In addition, configuration is implemented in 216 * the following Classes: 217 * 218 * CLASSES 219 * 220 * AbstractObjective 221 * Expression 222 * Poold 223 * SystemSolver 224 * 225 * (NB: Some classes were mentioned in multiple categories where there 226 * responsbilities overlap. Inner classes are not listed as their 227 * responsibilities can be clearly inferred from their context.) 228 * 229 * For more details on any of the packages, classes or interfaces 230 * mentioned above, look at the documentation associated with each 231 * class. 232 */ 233 234 /** 235 * The <code>Poold</code> class implements a dynamic resource 236 * allocation system for Solaris. 237 * 238 * <code>Poold</code> is a monitoring daemon, designed to evaluate 239 * user specified objectives, monitor workload behaviour and 240 * dynamically assign resources in order to satisfy the evaluated 241 * objectives. For more details see: 242 * 243 * <a href="http://sac.eng.sun.com/PSARC/2002/287/">PSARC/2002/287</a> 244 */ 245 final class Poold 246 { 247 /** 248 * The configuration which is manipulated. 249 */ 250 private Configuration conf; 251 252 /** 253 * The monitoring interface. 254 */ 255 private Monitor monitor; 256 257 /** 258 * The interface to higher level resource managers. 259 */ 260 private DRM drm; 261 262 /** 263 * The interface to the configuration solver. 264 */ 265 private Solver solver; 266 267 /** 268 * Default path to the logging properties file. 269 */ 270 public static final String POOLD_PROPERTIES_PATH = 271 "/usr/lib/pool/poold.properties"; 272 273 /** 274 * Logger for records which aren't produced in the Monitoring, 275 * Configuration, or Optimization states. This logger is the 276 * parent to the loggers used in those states. 277 */ 278 public static final Logger BASE_LOG = Logger.getLogger( 279 "com.sun.solaris.domain.pools.poold"); 280 281 /** 282 * Logger for records produced in the Configuration state. 283 */ 284 public static final Logger CONF_LOG = Logger.getLogger( 285 "com.sun.solaris.domain.pools.poold.Configuration"); 286 287 /** 288 * Logger for records produced in the Monitoring state. 289 */ 290 public static final Logger MON_LOG = Logger.getLogger( 291 "com.sun.solaris.domain.pools.poold.Monitoring"); 292 293 /** 294 * Logger for records produced in the Optimization state. 295 */ 296 public static final Logger OPT_LOG = Logger.getLogger( 297 "com.sun.solaris.domain.pools.poold.Optimization"); 298 299 /** 300 * Singleton instance of Poold. 301 */ 302 private static Poold instance; 303 304 /** 305 * The main sampling and solving thread. 306 */ 307 private Thread mainThread; 308 309 /** 310 * Process exit code indicating a failure. 311 */ 312 private static final int E_PO_FAILURE = 2; 313 314 /** 315 * Keep track of whether initialize() has been invoked, to 316 * output the "starting" message on the first. 317 */ 318 private AtomicBoolean firstInitialization = new AtomicBoolean(true); 319 320 /** 321 * Flags whether poold should run or exit. 322 */ 323 private AtomicBoolean shouldRun = new AtomicBoolean(true); 324 325 private static class logHelper { 326 /** 327 * Default logfile location 328 */ 329 public static final String DEF_LOG_LOC = "/var/log/pool/poold"; 330 331 /** 332 * Log location indicating <code>syslog</code>, as 333 * opposed to a file, should be used. 334 */ 335 public static final String SYSLOG_LOG_LOC = "SYSLOG"; 336 337 /** 338 * Default Log severity (if not overridden) 339 */ 340 public static final Severity DEF_SEVERITY = Severity.INFO; 341 342 /** 343 * Name of configuration property, log location. 344 */ 345 public static final String PROPERTY_NAME_LOG_LOC = 346 "system.poold.log-location"; 347 348 /** 349 * Name of configuration property, log level. 350 */ 351 public static final String PROPERTY_NAME_LOG_LEVEL = 352 "system.poold.log-level"; 353 354 /** 355 * Location of logfile -- an absolute filename, or 356 * "SYSLOG". 357 */ 358 private static String location; 359 360 /** 361 * Logfile handler, responsible for taking log messages 362 * and exporting them. 363 */ 364 private static Handler handler; 365 366 /** 367 * Logfile severity, log messages below this severity are 368 * ignored. 369 */ 370 private static Severity severity; 371 372 /** 373 * Flag recording whether preinitialization has occurred. 374 */ 375 private static boolean preinitialized = false; 376 377 /** 378 * Flag recording whether the logging Severity has been 379 * overridden with the -l command-line option, which 380 * means the console is the only thing being logged to, 381 * and the configuration's logging properties are 382 * ignored. 383 */ 384 private static boolean usingConsole; 385 386 /** 387 * Indicates whether logging semantics should be changed 388 * to facilitate debugging. 389 */ 390 private static final boolean loggingDebugging = false; 391 392 /** 393 * Do the pre-initialization initialization: install 394 * loggers for reporting errors during initialization. 395 * 396 * @param consoleSeverity If non-null, indicates that 397 * the configuration property-controlled logging behavior 398 * is to be overridden (the <code>-l</code> option was 399 * specified), and messages are to be logged only to the 400 * console, with (at most) the given maximum severity. 401 */ 402 private static void preinitialize(Severity consoleSeverity) { 403 if (preinitialized) 404 return; 405 406 /* 407 * Read logging properties affecting the 408 * FileHandler and ConsoleHandler from 409 * <code>poold.properties</code>. 410 */ 411 Properties props = new Properties(); 412 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 413 try { 414 props.load( 415 new FileInputStream(POOLD_PROPERTIES_PATH)); 416 props.store(bos, ""); 417 LogManager.getLogManager().readConfiguration( 418 new ByteArrayInputStream( 419 bos.toByteArray())); 420 } catch (IOException ioe) { 421 Poold.MON_LOG.log(Severity.WARNING, "could not " 422 + "read logging properties from " 423 + "poold.properties: " + ioe); 424 } 425 426 if (consoleSeverity == null || loggingDebugging) { 427 /* 428 * Log messages to /var/log/pool/poold, 429 * the default location, until the pools 430 * configuration properties are read and 431 * applied, which may change the logging 432 * file and severity. 433 * 434 * Under normal circumstances, it's 435 * expected that NO INFO-level messages 436 * will be emitted until that time; this 437 * is only a measure to ensure that 438 * unanticipated errors are reported in 439 * some log. 440 */ 441 location = SYSLOG_LOG_LOC; 442 handler = SyslogHandler.getInstance("poold", 443 Facility.DAEMON); 444 severity = DEF_SEVERITY; 445 handler.setLevel(severity); 446 BASE_LOG.addHandler(handler); 447 } 448 449 if (consoleSeverity != null) { 450 /* 451 * If -l is specified, log to the 452 * console. Unless loggingDebug is 453 * true, this will also mean that the 454 * logging properties are ignored. 455 * 456 * Determine if the user has specified 457 * the use of a ConsoleHandler through 458 * poold.properties. 459 */ 460 Logger root = Logger.getLogger(""); 461 Handler[] handler = root.getHandlers(); 462 ConsoleHandler ch = null; 463 for (int i = 0; i < handler.length && ch == 464 null; i++) 465 if (handler[i] 466 instanceof ConsoleHandler) 467 ch = (ConsoleHandler)handler[i]; 468 /* 469 * If none was previously, install a 470 * ConsoleHandler. 471 */ 472 if (ch == null) { 473 ch = new ConsoleHandler(); 474 475 ch.setFormatter( 476 new SysloglikeFormatter()); 477 ch.setLevel(consoleSeverity); 478 root.addHandler(ch); 479 } 480 severity = consoleSeverity; 481 BASE_LOG.log(Severity.DEBUG, 482 "logging with level " + severity); 483 484 /** 485 * Allow logging properties to be 486 * effective if loggingDebugging is not 487 * set. 488 */ 489 if (!loggingDebugging) 490 usingConsole = true; 491 } 492 preinitialized = true; 493 } 494 495 /** 496 * Configure loggers based on the logging-related 497 * configuration properties. Outputs a description of 498 * any changes to the configuration logger. 499 * 500 * @throws ConfigurationException if there is an error 501 * applying libpool configuration properties to 502 * <code>poold</code> 503 */ 504 public static void initializeWithConfiguration( 505 Configuration conf) throws ConfigurationException 506 { 507 String newLogLocation; 508 Severity newLogSeverity; 509 String newLogSeverityName = null; 510 511 /* 512 * Set the log location as specified by the 513 * configuration's system properties. 514 */ 515 try { 516 newLogLocation = conf.getStringProperty( 517 PROPERTY_NAME_LOG_LOC); 518 } catch (PoolsException e) { 519 newLogLocation = DEF_LOG_LOC; 520 } 521 522 try { 523 newLogSeverityName = conf.getStringProperty( 524 PROPERTY_NAME_LOG_LEVEL); 525 newLogSeverity = Severity.getSeverityWithName( 526 newLogSeverityName); 527 assert(newLogSeverity != null); 528 } catch (PoolsException e) { 529 newLogSeverity = DEF_SEVERITY; 530 } catch (IllegalArgumentException e) { 531 throw(ConfigurationException) 532 (new ConfigurationException( 533 "invalid " + PROPERTY_NAME_LOG_LEVEL + 534 "value: " + newLogSeverityName) 535 .initCause(e)); 536 } 537 538 Handler newLogHandler = null; 539 540 /* 541 * (Re)install the logger for the poold class 542 * hierarchy. This means that only poold 543 * messages are controlled by the pools 544 * configuration properties/command-line 545 * options. 546 */ 547 548 /* 549 * The logfile is always re-opened, in case the 550 * cause for reinitialization is due to SIGHUP 551 * following a log rotation. 552 */ 553 if (handler != null) { 554 BASE_LOG.removeHandler(handler); 555 handler.close(); 556 handler = null; 557 } 558 559 if (newLogLocation.toUpperCase().equals( 560 SYSLOG_LOG_LOC.toUpperCase())) 561 newLogHandler = 562 SyslogHandler.getInstance("poold", 563 Facility.DAEMON); 564 else { 565 if (!newLogLocation.startsWith("/")) 566 throw 567 new ConfigurationException( 568 PROPERTY_NAME_LOG_LOC + 569 " value is not an" + 570 " absolute path"); 571 try { 572 newLogHandler = 573 new FileHandler( 574 newLogLocation, 0, 1, true); 575 newLogHandler.setFormatter( 576 new SysloglikeFormatter()); 577 } catch (java.io.IOException ioe) { 578 Poold.utility.die( 579 Poold.CONF_LOG, 580 new PooldException( 581 newLogLocation + 582 ": can't write") 583 .initCause(ioe), false); 584 } 585 } 586 587 if (!severity.equals(newLogSeverity) || 588 !location.equals(newLogLocation)) 589 CONF_LOG.log(Severity.DEBUG, 590 "logging with level " + severity); 591 592 severity = newLogSeverity; 593 handler = newLogHandler; 594 location = newLogLocation; 595 596 handler.setLevel(severity); 597 BASE_LOG.addHandler(handler); 598 } 599 600 /** 601 * Configure the loggers based on the pool's logging 602 * properties, or, if the -l option was specified on the 603 * command line, continue to use the console. 604 */ 605 public static void initialize(Configuration conf) 606 throws ConfigurationException 607 { 608 if (usingConsole) 609 return; 610 else 611 initializeWithConfiguration(conf); 612 } 613 614 /** 615 * Return the current logging level. 616 */ 617 public static Severity getSeverity() 618 { 619 return (severity); 620 } 621 622 public static void close() 623 { 624 if (handler != null) { 625 BASE_LOG.removeHandler(handler); 626 handler.close(); 627 } 628 } 629 } 630 631 /** 632 * Constructor 633 * 634 * Only one poold instance should be running per system. 635 * 636 * @param consoleSeverity If non-null, indicates that the 637 * configuration property-controlled logging behavior is to be 638 * overridden (the <code>-l</code> option was specified), and 639 * messages are to be logged only to the console, with (at most) 640 * the given maximum severity. 641 */ 642 private Poold(Severity consoleSeverity) 643 { 644 /* 645 * Establish loggers for recording errors during 646 * initialization. Under normal circumstances, no 647 * messages will be emitted; this is only a measure to 648 * make sure that unanticipated errors are reported in 649 * some log, or the console, if the -l option is used. 650 */ 651 logHelper.preinitialize(consoleSeverity); 652 653 /* 654 * Try opening the configuration read-write in hopes the 655 * ability will be possessed henceforth. 656 */ 657 try { 658 conf = new Configuration(PoolInternal. 659 pool_dynamic_location(), PoolInternal.PO_RDWR); 660 conf.close(); 661 } catch (PoolsException pe) { 662 Poold.utility.die(CONF_LOG, new PooldException( 663 "cannot open dynamic pools configuration " + 664 "read-write (" + pe.getMessage() + ")") 665 .initCause(pe), false); 666 } 667 668 try { 669 conf = new Configuration(PoolInternal. 670 pool_dynamic_location(), PoolInternal.PO_RDONLY); 671 } catch (PoolsException pe) { 672 Poold.utility.die(CONF_LOG, pe); 673 } 674 675 /* 676 * Create the required sub-components: 677 * - a monitoring object 678 * - a DRM implementer 679 * - a solver 680 */ 681 monitor = new SystemMonitor(); 682 drm = new LogDRM(); 683 solver = new SystemSolver(monitor); 684 } 685 686 /** 687 * Returns a reference to the singleton <code>Poold</code>, 688 * constructing one if necessary. 689 * 690 * @param consoleSeverity If non-null, indicates that the 691 * configuration property-controlled logging behavior is to be 692 * overridden (the <code>-l</code> option was specified), and 693 * messages are to be logged only to the console, with (at most) 694 * the given maximum severity. 695 * @throws IllegalArgumentException if the given console 696 * severity doesn't match that of an existing instance. 697 */ 698 public static Poold getInstanceWithConsoleLogging( 699 Severity consoleSeverity) 700 { 701 if (instance == null) 702 return (instance = new Poold(consoleSeverity)); 703 else 704 if (logHelper.usingConsole == false && 705 consoleSeverity == null || consoleSeverity != 706 null && logHelper.getSeverity().equals( 707 consoleSeverity)) 708 return (instance); 709 else 710 throw new IllegalArgumentException(); 711 } 712 713 /** 714 * Initializes <code>Poold</code> for operation at startup or 715 * in response to a detected libpool configuration change. 716 */ 717 private void initialize() 718 { 719 try { 720 logHelper.initialize(conf); 721 if (firstInitialization.get()) 722 CONF_LOG.log(Severity.INFO, "starting"); 723 /* 724 * When a system is extremely busy, it may 725 * prove difficult to initialize poold. Just 726 * keep trying until we succeed. 727 */ 728 boolean busy = true; 729 while (busy && shouldRun.get()) { 730 busy = false; 731 try { 732 monitor.initialize(conf); 733 CONF_LOG.log(Severity.DEBUG, 734 "configuring solver..."); 735 solver.initialize(conf); 736 CONF_LOG.log(Severity.INFO, 737 "configuration complete"); 738 } catch (PoolsException pe) { 739 CONF_LOG.log(Severity.INFO, 740 "The system is too busy to " + 741 "initialize, attempting " + 742 "initialization again"); 743 /* 744 * pause for a while before 745 * re-attempting the 746 * initialization. 747 */ 748 try { 749 Thread.sleep(50); 750 } catch (InterruptedException ie) { 751 /* 752 * Safe to ignore this 753 * exception as we 754 * will simply try 755 * again sooner. 756 */ 757 } 758 busy = true; 759 } catch (StaleMonitorException sme) { 760 CONF_LOG.log(Severity.INFO, 761 "The system is too busy to " + 762 "initialize, attempting " + 763 "initialization again"); 764 /* 765 * pause for a while before 766 * re-attempting the 767 * initialization. 768 */ 769 try { 770 Thread.sleep(50); 771 } catch (InterruptedException ie) { 772 /* 773 * Safe to ignore this 774 * exception as we 775 * will simply try 776 * again sooner. 777 */ 778 } 779 busy = true; 780 } 781 } 782 if (firstInitialization.get()) 783 firstInitialization.set(false); 784 } catch (ConfigurationException ce) { 785 Poold.utility.die(CONF_LOG, ce); 786 } 787 } 788 789 /** 790 * Execute <code>Poold</code> indefinitely. This method is 791 * invoked after <code>Poold</code> completes 792 * configuration. It will continue to execute until 793 * <code>Poold</code> is terminated. 794 * 795 * @throws Exception If an there is an error in execution. 796 */ 797 private void execute() throws Exception 798 { 799 int changed = 0; 800 boolean confRequired = false; 801 802 while (shouldRun.get()) { 803 try { 804 changed = conf.update(); 805 assert(!confRequired || confRequired && 806 changed != 0); 807 if (changed != 0) { 808 CONF_LOG.log(Severity.DEBUG, 809 "configuration change detected"); 810 if (!confRequired) 811 CONF_LOG.log(Severity.INFO, 812 "configuration changed " + 813 "externally"); 814 CONF_LOG.log(Severity.INFO, 815 "reconfiguring..."); 816 } 817 confRequired = false; 818 } catch (PoolsException pe) { 819 Poold.utility.die(CONF_LOG, pe); 820 } 821 if (changed != 0) 822 initialize(); 823 824 boolean gotNext = false; 825 while (shouldRun.get() && !gotNext) { 826 try { 827 monitor.getNext(); 828 gotNext = true; 829 830 /* 831 * All workload-dependent 832 * objectives must now be 833 * checked for violations. The 834 * solver holds all objectives 835 * and it makes the decision 836 * about whether a 837 * reconfiguration is required. 838 */ 839 if (solver.examine(monitor)) { 840 MON_LOG.log(Severity.INFO, 841 "reconfiguration required"); 842 confRequired = solver.solve(); 843 } else { 844 MON_LOG.log(Severity.INFO, 845 "all evaluated objectives" 846 + " satisfied"); 847 } 848 } catch (StaleMonitorException e) { 849 /* 850 * Later, assert that every 851 * cause of the 852 * StaleMonitorException is 853 * handled by the above 854 * conf.update(). 855 */ 856 confRequired = true; 857 } catch (InterruptedException ie) { 858 Poold.MON_LOG.log(Severity.INFO, 859 "interrupted"); 860 break; 861 } 862 } 863 if (!shouldRun.get()) 864 break; 865 System.runFinalization(); 866 } 867 Poold.BASE_LOG.log(Severity.NOTICE, "exiting"); 868 } 869 870 /** 871 * Cleanup any resources when the application terminates. 872 */ 873 private void cleanup() 874 { 875 conf.close(); 876 logHelper.close(); 877 instance = null; 878 } 879 880 /** 881 * Invoke <code>Poold</code>. This main function is provided 882 * so that <code>poold</code> can be executed. Execution will 883 * continue indefinitely unless there is an error, in which case 884 * when execute() terminates. 885 */ 886 public void run() 887 { 888 mainThread = Thread.currentThread(); 889 890 Runtime.getRuntime().addShutdownHook(new Thread() { 891 public void run() { 892 try { 893 cleanup(); 894 } catch (Throwable t) { 895 } 896 } 897 }); 898 899 try { 900 initialize(); 901 execute(); 902 } catch (Throwable t) { 903 Poold.utility.die(BASE_LOG, t); 904 } 905 } 906 907 /** 908 * Stops <code>Poold</code>. Sets a flag indicating that run() 909 * should break out of the monitor/solve loop and clean up. 910 */ 911 public void shutdown() { 912 /* 913 * Flag that the main thread should break out of the 914 * sample/solve loop as soon as possible. 915 */ 916 shouldRun.set(false); 917 918 /* 919 * Interrupt the main thread, which will cause the 920 * monitor to break out of its sleep if it's waiting for 921 * the sample time to arrive, and cause the sample/solve 922 * loop condition to be evaluated sooner. But make some 923 * effort not to cause an InterruptedIOException if 924 * we're not even through initialization yet; we'll get 925 * around to shutting down soon enough. 926 */ 927 if (!firstInitialization.get() && mainThread != null) 928 mainThread.interrupt(); 929 } 930 931 public static void main(String args[]) throws IllegalArgumentException 932 { 933 Severity severity = null; 934 935 if (args.length > 0) { 936 if (args[0].compareTo("-l") == 0 && args.length == 2) { 937 severity = (Severity) Severity.parse(args[1]); 938 } else 939 throw new IllegalArgumentException( 940 "usage: poold [-l level]"); 941 } 942 Poold p = getInstanceWithConsoleLogging(severity); 943 p.run(); 944 } 945 946 /** 947 * The <code>utility</code> class provides various 948 * <code>Poold</code> related static utility methods that 949 * don't naturally reside on any class. 950 */ 951 static class utility { 952 /** 953 * Outputs a near-final message corresponding 954 * to an exception (or other throwable) to the named 955 * logger before causing the VM to exit. The message 956 * will have ERROR severity unless an instance of 957 * PoolsException is given, in which case the message 958 * will adopt the PoolsException's severity. Similarly, 959 * if the PoolsException specifies an exit code, it will 960 * be used; otherwise the default of 961 * <code>E_PO_FAILURE</code> will be used. 962 * 963 * @param logger Logger used to log the message 964 * @param t The cause. A stack trace will be affixed to 965 * the message. 966 */ 967 public static void die(Logger logger, Throwable t) 968 { 969 die(logger, t, true); 970 } 971 972 /** 973 * Outputs a near-final message corresponding 974 * to an exception (or other throwable) to the named 975 * logger before causing the VM to exit. The message 976 * will have ERROR severity unless an instance of 977 * PoolsException is given, in which case the message 978 * will adopt the PoolsException's severity. Similarly, 979 * if the PoolsException specifies an exit code, it will 980 * be used; otherwise the default of 981 * <code>E_PO_FAILURE</code> will be used. 982 * 983 * @param logger Logger used to log the message 984 * @param t The cause. 985 * @param showStackTrace If true, a stack trace will be 986 * affixed to the message. 987 */ 988 public static void die(Logger logger, Throwable t, 989 boolean showStackTrace) 990 { 991 try { 992 Severity severity; 993 /* 994 * Configure the message's exception and 995 * severity. 996 */ 997 LogRecord record; 998 if (t instanceof PooldException) 999 record = new LogRecord( 1000 ((PooldException)t).getSeverity(), 1001 t.getMessage()); 1002 else 1003 record = new LogRecord(Severity.ERR, 1004 t.getMessage()); 1005 if (record.getMessage() == null) 1006 record.setMessage("exception " + 1007 t.getClass().getName()); 1008 if (showStackTrace) 1009 record.setThrown(t); 1010 1011 record.setLoggerName(logger.getName()); 1012 logger.log(record); 1013 1014 if (logHelper.handler != null) 1015 logHelper.handler.flush(); 1016 if (t instanceof PooldException) 1017 System.exit(((PooldException)t) 1018 .getExitCode()); 1019 else 1020 System.exit(E_PO_FAILURE); 1021 } catch (Exception e) { 1022 SuccinctStackTraceFormatter.printStackTrace(e); 1023 System.exit(-1); 1024 } 1025 } 1026 1027 /** 1028 * Outputs a warning-level message to the named logger. 1029 * 1030 * @param logger Logger used to log the message 1031 * @param t The cause. 1032 * @param showStackTrace If true, a stack trace will be 1033 * affixed to the message. 1034 */ 1035 public static void warn(Logger logger, Throwable t, 1036 boolean showStackTrace) 1037 { 1038 try { 1039 Severity severity; 1040 /* 1041 * Configure the message's exception and 1042 * severity. 1043 */ 1044 LogRecord record; 1045 if (t instanceof PooldException) 1046 record = new LogRecord( 1047 ((PooldException)t).getSeverity(), 1048 t.getMessage()); 1049 else 1050 record = new LogRecord(Severity.WARNING, 1051 t.getMessage()); 1052 if (record.getMessage() == null) 1053 record.setMessage("exception " + 1054 t.getClass().getName()); 1055 if (showStackTrace) 1056 record.setThrown(t); 1057 1058 record.setLoggerName(logger.getName()); 1059 logger.log(record); 1060 1061 if (logHelper.handler != null) 1062 logHelper.handler.flush(); 1063 } catch (Exception e) { 1064 SuccinctStackTraceFormatter.printStackTrace(e); 1065 System.exit(-1); 1066 } 1067 } 1068 } 1069 } 1070 1071 class ConfigurationException extends Exception 1072 { 1073 public ConfigurationException(String message) 1074 { 1075 super(message); 1076 } 1077 } 1078 1079 class IllegalOFValueException extends RuntimeException 1080 { 1081 public IllegalOFValueException(String message) 1082 { 1083 super(message); 1084 } 1085 } 1086 1087 class PooldException extends Exception { 1088 /** 1089 * The exit code which the virtual machine should exit at if 1090 * this exception cannot be handled. 1091 */ 1092 private int exitCode; 1093 1094 /** 1095 * The severity of this message. See <code>Severity</code>. 1096 */ 1097 private Severity severity; 1098 1099 /** 1100 * Constructs a message with default exit code and 1101 * <code>System.ERR</code> severity. 1102 */ 1103 public PooldException(String message) 1104 { 1105 this(message, 1, Severity.ERR); 1106 } 1107 1108 /** 1109 * Constructs a message with given exit code and 1110 * <code>System.ERR</code> severity. 1111 */ 1112 public PooldException(String message, int exitCode) 1113 { 1114 this(message, exitCode, Severity.ERR); 1115 } 1116 1117 /** 1118 * Constructs a message with a given exit code and severity. 1119 */ 1120 public PooldException(String message, int exitCode, Severity severity) 1121 { 1122 super(message); 1123 this.exitCode = exitCode; 1124 this.severity = severity; 1125 } 1126 1127 /** 1128 * The exit code which the virtual machine should exit at if 1129 * this exception cannot be handled. 1130 */ 1131 public int getExitCode() 1132 { 1133 return (exitCode); 1134 } 1135 1136 public Severity getSeverity() 1137 { 1138 return (severity); 1139 } 1140 } 1141