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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2001 by Sun Microsystems, Inc. 23 * All rights reserved. 24 * 25 * DataModel.java 26 */ 27 28 package com.sun.wbem.solarisprovider.srm; 29 30 import java.util.HashMap; 31 import java.util.Vector; 32 import java.util.Iterator; 33 34 35 /** 36 * Aggregation of all users, projects, and sets metrics data. 37 * Implements the singleton pattern 38 * @author Sun Microsystems, Inc. 39 */ 40 class DataModel { 41 42 private static DataModel dm; 43 private static SRMDataReader dr; 44 private static boolean doAlive; 45 /** 46 * syncObject guards the calls of SRMDataReader methods between the 47 * current data model thread and the KeepAlive thread. 48 */ 49 private static Object syncObject; 50 /** 51 * rdsKeepAliveTimeout: how long the KeepAlive thread should keep 52 * the connection opened. 53 */ 54 private static int rdsKeepAliveTimeout = 30 * 60000; 55 private static KeepAlive ka; 56 private static boolean kaError; 57 private static boolean msacct = false; 58 59 private static final int PROCESSESHASHSIZE = 500; 60 private static final int USERPROCSHASHSIZE = 200; 61 private static final int PROJPROCSHASHSIZE = 100; 62 private static final int USERSHASHSIZE = 200; 63 private static final int PROJSHASHSIZE = 100; 64 private static final int L_PRC_SI = 1; 65 private static final int L_USR_SI = 2; 66 private static final int L_PRJ_SI = 3; 67 private static final int L_AC_USR = 4; 68 private static final int L_AC_PRJ = 5; 69 private static final int L_SYSTEM = 6; 70 private static final int L_ALL = 20; 71 72 // RDS exec command 73 private static final String RDSPGM = "/usr/sadm/lib/wbem/rds"; 74 75 private static final int TIMEOUTIDX = 3; 76 private static final int INTERVALIDX = 5; 77 78 // RDS commands 79 private static final String CMD_GETALL = "-pUuJjS"; 80 private static final String CMD_GETPL = "-p"; 81 private static final String CMD_GETUL = "-u"; 82 private static final String CMD_GETAUL = "-U"; 83 private static final String CMD_GETJL = "-j"; 84 private static final String CMD_GETAJL = "-J"; 85 private static final String CMD_GETASL = "-S"; 86 private static final String CMD_ALIVE = "alive"; 87 private static final String CMD_EXIT = "exit"; 88 89 private static boolean updating; // set if udpdateing is in progress 90 private static boolean running; // set if the rds is running 91 92 private int rdsTimeout; 93 private int rdsInterval; 94 private String rdsArgs[]; 95 protected HashMap processes = new HashMap(PROCESSESHASHSIZE); 96 protected HashMap users = new HashMap(USERSHASHSIZE); 97 protected HashMap userprocs = new HashMap(USERPROCSHASHSIZE); 98 protected HashMap projs = new HashMap(PROJSHASHSIZE); 99 protected HashMap projprocs = new HashMap(PROJPROCSHASHSIZE); 100 protected SystemDataModel sdm = new SystemDataModel(); 101 102 /** 103 * Default constructor 104 */ 105 private DataModel() { 106 } 107 108 /** 109 * Should be used to obtain the singleton instance of this class 110 * @return the singleton instance of this class 111 */ 112 static DataModel getHandle(Object syncObj) { 113 114 if (dm == null) { 115 dm = new DataModel(); 116 dr = new SRMDataReader(dm); 117 syncObject = syncObj; 118 try { 119 if (Util.propertyKEEPALIVETIMEOUT != null) { 120 rdsKeepAliveTimeout = 121 Integer.parseInt(Util.propertyKEEPALIVETIMEOUT); 122 } 123 if (Util.propertyMSACCT != null) { 124 msacct = Util.propertyMSACCT.equalsIgnoreCase("true"); 125 } 126 } catch (Exception e) { }; 127 } 128 return dm; 129 } 130 131 /** 132 * Initialize the rds timeouts, the actually opening is deleted 133 * until the first update call. 134 */ 135 void open(int rdsTimeout, int rdsInterval) { 136 Vector args = new Vector(6); 137 String dbfile = null; 138 139 this.rdsTimeout = rdsTimeout; 140 this.rdsInterval = rdsInterval; 141 args.add(RDSPGM); 142 args.add("-a"); 143 args.add("-t"); 144 args.add(""+rdsTimeout); 145 args.add("-i"); 146 args.add(""+rdsInterval); 147 if (Util.propertyRDSDATABASE != null) { 148 args.add("-f"); 149 args.add(Util.propertyRDSDATABASE); 150 } 151 if (Util.propertyMSACCT != null && 152 Util.propertyMSACCT.equalsIgnoreCase("true")) { 153 args.add("-m"); 154 } 155 if (Util.propertyRDSLOGFILE != null) { 156 args.add("-L"); 157 args.add(Util.propertyRDSLOGFILE); 158 } 159 rdsArgs = new String[args.size()]; 160 args.toArray(rdsArgs); 161 162 } // end open 163 164 /** 165 * Close the rds communication pipe. 166 */ 167 void close() { 168 169 if (running) { 170 doAlive = false; 171 ka.interrupt(); 172 synchronized (syncObject) { 173 /* 174 * check again, since AliveThread could already close RDS 175 * when this thread was waiting on syncObject 176 */ 177 if (running) { 178 dr.closeRDS(); 179 running = false; 180 } 181 } 182 } 183 184 } // end close 185 186 /** 187 * Close the rds communication pipe after an error has raised. In this 188 * case the rds will be shutdown instead of gently closed. 189 */ 190 void closeONError() { 191 doAlive = false; 192 ka.interrupt(); 193 dr.shutdownRDS(); 194 running = false; 195 } 196 197 /** 198 * Get a provider data model object identified by id from the list defined 199 * by listt. 200 * @return the provider data model object or null if other the list type 201 * or the provider object id are unsupported. 202 */ 203 SRMProviderDataModel getProviderDataModel(int listt, String id) { 204 205 try { 206 switch (listt) { 207 case L_PRC_SI : return getProcess(Integer.parseInt(id)); 208 case L_USR_SI : return getUserprocs(id); 209 case L_PRJ_SI : return getProjprocs(id); 210 case L_AC_USR : return getUser(id); 211 case L_AC_PRJ : return getProject(id); 212 case L_SYSTEM : return sdm; 213 default: return null; 214 } 215 } catch (NumberFormatException e) { 216 return null; 217 } 218 } 219 220 /** 221 * Get process metrics object. 222 * @param pid the process id 223 * @return metrics object with process metrics or new empty 224 * object at first call. 225 */ 226 ProcessDataModel getProcess(int pid) { 227 228 ProcessDataModel pdm = null; 229 Integer pidI = new Integer(pid); 230 231 if ((pdm = (ProcessDataModel) processes.get(pidI)) == null) { 232 if (updating == false) 233 return null; 234 pdm = new ProcessDataModel(pid); 235 processes.put(pidI, pdm); 236 } 237 if (updating == true) 238 pdm.setUpdated(true); 239 240 return pdm; 241 } 242 243 /** 244 * Get user metrics object. 245 * @param uid the user id 246 * @return metrics object with process metrics or new empty object at 247 * first call. 248 */ 249 UserProcessAggregateDataModel getUserprocs(String uidStr) { 250 251 UserProcessAggregateDataModel padm = null; 252 253 if ((padm = (UserProcessAggregateDataModel) 254 userprocs.get(uidStr)) == null) { 255 if (updating == false) 256 return null; 257 padm = new UserProcessAggregateDataModel(uidStr); 258 userprocs.put(uidStr, padm); 259 } 260 261 if (updating == true) 262 padm.setUpdated(true); 263 264 return padm; 265 } 266 267 /** 268 * Get project metrics object. 269 * @return metrics object with process metrics or new empty 270 * object at first call. 271 */ 272 ProjectProcessAggregateDataModel getProjprocs(String name) { 273 274 ProjectProcessAggregateDataModel padm = null; 275 276 if ((padm = (ProjectProcessAggregateDataModel) 277 projprocs.get(name)) == null) { 278 if (updating == false) 279 return null; 280 padm = new ProjectProcessAggregateDataModel(name); 281 projprocs.put(name, padm); 282 } 283 if (updating == true) 284 padm.setUpdated(true); 285 286 return padm; 287 } 288 289 /** 290 * Get active user object. 291 * @param name the user id as string 292 * @return active user object. 293 */ 294 ActiveUserModel getUser(String name) { 295 296 ActiveUserModel aum = null; 297 298 if ((aum = (ActiveUserModel) users.get(name)) == null) { 299 if (updating == false) 300 return null; 301 aum = new ActiveUserModel(name); 302 users.put(name, aum); 303 } 304 if (updating == true) 305 aum.setUpdated(true); 306 307 return aum; 308 } 309 310 /** 311 * Get active project object. 312 * @param name the project 313 * @return project object. 314 */ 315 ActiveProjectModel getProject(String name) { 316 317 ActiveProjectModel apm = null; 318 319 if ((apm = (ActiveProjectModel) projs.get(name)) == null) { 320 if (updating == false) 321 return null; 322 apm = new ActiveProjectModel(name); 323 projs.put(name, apm); 324 } 325 if (updating == true) 326 apm.setUpdated(true); 327 328 return apm; 329 } 330 331 /** 332 * Returns an iterator over the Processes. 333 * @return iterator 334 */ 335 Iterator getProcessIterator() { 336 return processes.values().iterator(); 337 } 338 339 /** 340 * Returns an iterator over the Users. 341 * @return iterator 342 */ 343 Iterator getUserIterator() { 344 return users.values().iterator(); 345 } 346 347 /** 348 * Returns an iterator over the Projects. 349 * @return iterator 350 */ 351 Iterator getProjectIterator() { 352 return projs.values().iterator(); 353 } 354 355 /** 356 * Returns an iterator over the user process aggregation. 357 * @return iterator 358 */ 359 Iterator getUserprocsIterator() { 360 return userprocs.values().iterator(); 361 } 362 363 /** 364 * Returns an iterator over the project process aggregation. 365 * @return iterator 366 */ 367 Iterator getProjprocsIterator() { 368 return projprocs.values().iterator(); 369 } 370 371 /** 372 * Update the metrics data. 373 * @exception SRMProtocolException 374 */ 375 void update() throws SRMProtocolException { 376 377 SRMProviderDataModel pdm; 378 int tries = 2; 379 380 while (tries-- > 0) { 381 if (!running) { 382 dr.startRDS(rdsArgs); 383 running = true; 384 ka = new KeepAlive(rdsKeepAliveTimeout); 385 ka.start(); 386 } 387 try { 388 synchronized (syncObject) { 389 /* check if AliveThread has set error flag */ 390 if (kaError) { 391 closeONError(); 392 continue; 393 /* 394 * check if rds is still running, since AliveThread 395 * could already close RDS when this thread was waiting 396 * on syncObject 397 */ 398 } else if (running) { 399 updating = true; 400 dr.getUpdate(CMD_GETALL); 401 } else { 402 tries = 2; 403 continue; 404 } 405 } 406 ka.resetTimeout(); 407 updating = false; 408 tries = 0; 409 } catch (SRMProtocolException e) { 410 SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage()); 411 closeONError(); 412 if (tries == 0) 413 throw e; 414 } 415 } 416 cleanUp(); 417 418 } // end update 419 420 /** 421 * Remove all dead processes, users or projects. 422 */ 423 private void cleanUp() { 424 425 cleanUpList(processes); 426 cleanUpList(users); 427 cleanUpList(userprocs); 428 cleanUpList(projs); 429 cleanUpList(projprocs); 430 } 431 432 /** 433 * Remove all elements that heven't been updated in last update. 434 */ 435 private void cleanUpList(HashMap map) { 436 Iterator i; 437 SRMProviderDataModel pdm; 438 439 for (i = map.values().iterator(); i.hasNext(); ) { 440 if (!((pdm = (SRMProviderDataModel) i.next()).isUpdated())) { 441 i.remove(); 442 } else { 443 pdm.setUpdated(false); 444 } 445 } 446 } 447 448 /** 449 * This thread keeps the rds and the communication with it alive by 450 * sending the alive message to rds. 451 */ 452 class KeepAlive extends Thread { 453 int keepAliveTimeout, save; 454 455 /** 456 * Constructor 457 * @param timeout how long to run at all 458 */ 459 public KeepAlive(int timeout) { 460 super("KeepAlive"); 461 kaError = false; 462 keepAliveTimeout = timeout; 463 save = keepAliveTimeout; 464 } 465 466 synchronized public void run() { 467 int myTimeout = 0; 468 int waitTime = rdsTimeout / 2; 469 470 doAlive = true; 471 472 while (doAlive) { 473 /* 474 * the keepAliveTimeout value is set in constructor and 475 * in the resetTimeout() method. If its value is reseted 476 * the internal timer myTimeout value will be wind up. 477 */ 478 if (keepAliveTimeout > 0) { 479 myTimeout = keepAliveTimeout; 480 keepAliveTimeout = 0; 481 } 482 try { 483 synchronized (syncObject) { 484 /* 485 * this thread has gained the sync object, but it 486 * also should check the doAlive flag since 487 * the dataModel thread could already removed it 488 * because of a protocol error 489 */ 490 if (doAlive) { 491 myTimeout -= waitTime; 492 kaError = true; 493 if (myTimeout <= 0) { 494 dr.closeRDS(); 495 running = false; 496 return; 497 } else { 498 dr.alive(); 499 } 500 kaError = false; 501 } else { 502 return; 503 } 504 } 505 wait(waitTime); 506 } catch (InterruptedException e) { 507 SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage()); 508 return; 509 } catch (SRMProtocolException e) { 510 SRMDebug.trace(SRMDebug.TRACE_ALL, e.getMessage()); 511 return; 512 } 513 } 514 } 515 516 /** 517 * Reset the absolute timeout 518 */ 519 public void resetTimeout() { 520 keepAliveTimeout = save; 521 } 522 523 } // end class KeepAlive 524 525 526 class ProjectProcessAggregateDataModel extends ProcessAggregateDataModel { 527 public ProjectProcessAggregateDataModel(String id) { 528 super(id); 529 } 530 531 protected void setCIMInstance(boolean newInstance) { 532 super.setCIMInstance(newInstance); 533 setStrProp(newInstance, CREATIONCLASSNAME, 534 SOLARIS_PROJECTPROCESSAGGREGATESTATISTICALINFORMATION); 535 setStrProp(newInstance, NAME, name); 536 } 537 } 538 539 class UserProcessAggregateDataModel extends ProcessAggregateDataModel { 540 public UserProcessAggregateDataModel(String id) { 541 super(id); 542 } 543 544 protected void setCIMInstance(boolean newInstance) { 545 super.setCIMInstance(newInstance); 546 setStrProp(newInstance, CREATIONCLASSNAME, 547 SOLARIS_USERPROCESSAGGREGATESTATISTICALINFORMATION); 548 setStrProp(newInstance, NAME, name); 549 } 550 } 551 552 } // end class DataModel 553