1 /* 2 * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.management.snmp.jvminstr; 26 27 // java imports 28 // 29 import com.sun.jmx.mbeanserver.Util; 30 import java.io.Serializable; 31 import java.util.List; 32 import java.util.Iterator; 33 import java.util.Map; 34 import java.util.HashMap; 35 import java.util.TreeMap; 36 import java.util.Collections; 37 38 // jmx imports 39 // 40 import javax.management.MBeanServer; 41 import javax.management.ObjectName; 42 import com.sun.jmx.snmp.SnmpOid; 43 import com.sun.jmx.snmp.SnmpStatusException; 44 45 // jdmk imports 46 // 47 import com.sun.jmx.snmp.agent.SnmpMib; 48 import com.sun.jmx.snmp.agent.SnmpStandardObjectServer; 49 import com.sun.jmx.snmp.agent.SnmpMibTable; 50 51 import java.lang.management.MemoryManagerMXBean; 52 import java.lang.management.MemoryPoolMXBean; 53 54 import sun.management.snmp.jvmmib.JvmMemMgrPoolRelTableMeta; 55 import sun.management.snmp.util.SnmpTableCache; 56 import sun.management.snmp.util.SnmpCachedData; 57 import sun.management.snmp.util.SnmpTableHandler; 58 import sun.management.snmp.util.MibLogger; 59 import sun.management.snmp.util.JvmContextFactory; 60 61 /** 62 * The class is used for implementing the "JvmMemMgrPoolRelTable" group. 63 */ 64 public class JvmMemMgrPoolRelTableMetaImpl extends JvmMemMgrPoolRelTableMeta 65 implements Serializable { 66 67 static final long serialVersionUID = 1896509775012355443L; 68 69 /** 70 * A concrete implementation of {@link SnmpTableCache}, for the 71 * jvmMemMgrPoolRelTable. 72 **/ 73 74 private static class JvmMemMgrPoolRelTableCache 75 extends SnmpTableCache { 76 77 static final long serialVersionUID = 6059937161990659184L; 78 final private JvmMemMgrPoolRelTableMetaImpl meta; 79 80 /** 81 * Create a weak cache for the jvmMemMgrPoolRelTable. 82 * @param validity validity of the cached data, in ms. 83 **/ 84 JvmMemMgrPoolRelTableCache(JvmMemMgrPoolRelTableMetaImpl meta, 85 long validity) { 86 this.validity = validity; 87 this.meta = meta; 88 } 89 90 /** 91 * Call <code>getTableDatas(JvmContextFactory.getUserData())</code>. 92 **/ 93 public SnmpTableHandler getTableHandler() { 94 final Map<Object,Object> userData = JvmContextFactory.getUserData(); 95 return getTableDatas(userData); 96 } 97 98 /** 99 * Builds a map pool-name => pool-index from the SnmpTableHandler 100 * of the JvmMemPoolTable. 101 **/ 102 private static Map<String, SnmpOid> buildPoolIndexMap(SnmpTableHandler handler) { 103 // optimization... 104 if (handler instanceof SnmpCachedData) 105 return buildPoolIndexMap((SnmpCachedData)handler); 106 107 // not optimizable... too bad. 108 final Map<String, SnmpOid> m = new HashMap<>(); 109 SnmpOid index=null; 110 while ((index = handler.getNext(index))!=null) { 111 final MemoryPoolMXBean mpm = 112 (MemoryPoolMXBean)handler.getData(index); 113 if (mpm == null) continue; 114 final String name = mpm.getName(); 115 if (name == null) continue; 116 m.put(name,index); 117 } 118 return m; 119 } 120 121 /** 122 * Builds a map pool-name => pool-index from the SnmpTableHandler 123 * of the JvmMemPoolTable. 124 * Optimized algorithm. 125 **/ 126 private static Map<String, SnmpOid> buildPoolIndexMap(SnmpCachedData cached) { 127 if (cached == null) return Collections.emptyMap(); 128 final SnmpOid[] indexes = cached.indexes; 129 final Object[] datas = cached.datas; 130 final int len = indexes.length; 131 final Map<String, SnmpOid> m = new HashMap<>(len); 132 for (int i=0; i<len; i++) { 133 final SnmpOid index = indexes[i]; 134 if (index == null) continue; 135 final MemoryPoolMXBean mpm = 136 (MemoryPoolMXBean)datas[i]; 137 if (mpm == null) continue; 138 final String name = mpm.getName(); 139 if (name == null) continue; 140 m.put(name,index); 141 } 142 return m; 143 } 144 145 /** 146 * Return a table handler that holds the jvmMemManagerTable table data. 147 * This method return the cached table data if it is still 148 * valid, recompute it and cache the new value if it's not. 149 * If it needs to recompute the cached data, it first 150 * try to obtain the list of memory managers from the request 151 * contextual cache, and if it is not found, it calls 152 * <code>ManagementFactory.getMemoryMBean().getMemoryManagers()</code> 153 * and caches the value. 154 * This ensures that 155 * <code>ManagementFactory.getMemoryMBean().getMemoryManagers()</code> 156 * is not called more than once per request, thus ensuring a 157 * consistent view of the table. 158 **/ 159 protected SnmpCachedData updateCachedDatas(Object userData) { 160 // Get the MemoryManager table 161 final SnmpTableHandler mmHandler = 162 meta.getManagerHandler(userData); 163 164 // Get the MemoryPool table 165 final SnmpTableHandler mpHandler = 166 meta.getPoolHandler(userData); 167 168 // Time stamp for the cache 169 final long time = System.currentTimeMillis(); 170 171 // Build a Map poolname -> index 172 final Map<String,SnmpOid> poolIndexMap = buildPoolIndexMap(mpHandler); 173 174 // For each memory manager, get the list of memory pools 175 // For each memory pool, find its index in the memory pool table 176 // Create a row in the relation table. 177 final TreeMap<SnmpOid, Object> table = 178 new TreeMap<>(SnmpCachedData.oidComparator); 179 updateTreeMap(table,userData,mmHandler,mpHandler,poolIndexMap); 180 181 return new SnmpCachedData(time,table); 182 } 183 184 185 /** 186 * Get the list of memory pool associated with the 187 * given MemoryManagerMXBean. 188 **/ 189 protected String[] getMemoryPools(Object userData, 190 MemoryManagerMXBean mmm, long mmarc) { 191 final String listTag = 192 "JvmMemManager." + mmarc + ".getMemoryPools"; 193 194 String[] result=null; 195 if (userData instanceof Map) { 196 result = (String[])((Map)userData).get(listTag); 197 if (result != null) return result; 198 } 199 200 if (mmm!=null) { 201 result = mmm.getMemoryPoolNames(); 202 } 203 if ((result!=null)&&(userData instanceof Map)) { 204 Map<Object, Object> map = Util.cast(userData); 205 map.put(listTag,result); 206 } 207 208 return result; 209 } 210 211 protected void updateTreeMap(TreeMap<SnmpOid, Object> table, Object userData, 212 MemoryManagerMXBean mmm, 213 SnmpOid mmIndex, 214 Map<String, SnmpOid> poolIndexMap) { 215 216 // The MemoryManager index is an int, so it's the first 217 // and only subidentifier. 218 final long mmarc; 219 try { 220 mmarc = mmIndex.getOidArc(0); 221 } catch (SnmpStatusException x) { 222 log.debug("updateTreeMap", 223 "Bad MemoryManager OID index: "+mmIndex); 224 log.debug("updateTreeMap",x); 225 return; 226 } 227 228 229 // Cache this in userData + get it from cache? 230 final String[] mpList = getMemoryPools(userData,mmm,mmarc); 231 if (mpList == null || mpList.length < 1) return; 232 233 final String mmmName = mmm.getName(); 234 for (int i = 0; i < mpList.length; i++) { 235 final String mpmName = mpList[i]; 236 if (mpmName == null) continue; 237 final SnmpOid mpIndex = poolIndexMap.get(mpmName); 238 if (mpIndex == null) continue; 239 240 // The MemoryPool index is an int, so it's the first 241 // and only subidentifier. 242 final long mparc; 243 try { 244 mparc = mpIndex.getOidArc(0); 245 } catch (SnmpStatusException x) { 246 log.debug("updateTreeMap","Bad MemoryPool OID index: " + 247 mpIndex); 248 log.debug("updateTreeMap",x); 249 continue; 250 } 251 // The MemoryMgrPoolRel table indexed is composed 252 // of the MemoryManager index, to which the MemoryPool 253 // index is appended. 254 final long[] arcs = { mmarc, mparc }; 255 256 final SnmpOid index = new SnmpOid(arcs); 257 258 table.put(index, new JvmMemMgrPoolRelEntryImpl(mmmName, 259 mpmName, 260 (int)mmarc, 261 (int)mparc)); 262 } 263 } 264 265 protected void updateTreeMap(TreeMap<SnmpOid, Object> table, Object userData, 266 SnmpTableHandler mmHandler, 267 SnmpTableHandler mpHandler, 268 Map<String, SnmpOid> poolIndexMap) { 269 if (mmHandler instanceof SnmpCachedData) { 270 updateTreeMap(table,userData,(SnmpCachedData)mmHandler, 271 mpHandler,poolIndexMap); 272 return; 273 } 274 275 SnmpOid mmIndex=null; 276 while ((mmIndex = mmHandler.getNext(mmIndex))!=null) { 277 final MemoryManagerMXBean mmm = 278 (MemoryManagerMXBean)mmHandler.getData(mmIndex); 279 if (mmm == null) continue; 280 updateTreeMap(table,userData,mmm,mmIndex,poolIndexMap); 281 } 282 } 283 284 protected void updateTreeMap(TreeMap<SnmpOid, Object> table, Object userData, 285 SnmpCachedData mmHandler, 286 SnmpTableHandler mpHandler, 287 Map<String, SnmpOid> poolIndexMap) { 288 289 final SnmpOid[] indexes = mmHandler.indexes; 290 final Object[] datas = mmHandler.datas; 291 final int size = indexes.length; 292 for (int i=size-1; i>-1; i--) { 293 final MemoryManagerMXBean mmm = 294 (MemoryManagerMXBean)datas[i]; 295 if (mmm == null) continue; 296 updateTreeMap(table,userData,mmm,indexes[i],poolIndexMap); 297 } 298 } 299 } 300 301 // The weak cache for this table. 302 protected SnmpTableCache cache; 303 304 private transient JvmMemManagerTableMetaImpl managers = null; 305 private transient JvmMemPoolTableMetaImpl pools = null; 306 307 /** 308 * Constructor for the table. Initialize metadata for 309 * "JvmMemMgrPoolRelTableMeta". 310 * The reference on the MBean server is updated so the entries 311 * created through an SNMP SET will be AUTOMATICALLY REGISTERED 312 * in Java DMK. 313 */ 314 public JvmMemMgrPoolRelTableMetaImpl(SnmpMib myMib, 315 SnmpStandardObjectServer objserv) { 316 super(myMib,objserv); 317 this.cache = new 318 JvmMemMgrPoolRelTableCache(this,((JVM_MANAGEMENT_MIB_IMPL)myMib). 319 validity()); 320 } 321 322 // Returns a pointer to the JvmMemManager meta node - we're going 323 // to reuse its SnmpTableHandler in order to implement the 324 // relation table. 325 private final JvmMemManagerTableMetaImpl getManagers(SnmpMib mib) { 326 if (managers == null) { 327 managers = (JvmMemManagerTableMetaImpl) 328 mib.getRegisteredTableMeta("JvmMemManagerTable"); 329 } 330 return managers; 331 } 332 333 // Returns a pointer to the JvmMemPool meta node - we're going 334 // to reuse its SnmpTableHandler in order to implement the 335 // relation table. 336 private final JvmMemPoolTableMetaImpl getPools(SnmpMib mib) { 337 if (pools == null) { 338 pools = (JvmMemPoolTableMetaImpl) 339 mib.getRegisteredTableMeta("JvmMemPoolTable"); 340 } 341 return pools; 342 } 343 344 /** 345 * Returns the JvmMemManagerTable SnmpTableHandler 346 **/ 347 protected SnmpTableHandler getManagerHandler(Object userData) { 348 final JvmMemManagerTableMetaImpl managerTable = getManagers(theMib); 349 return managerTable.getHandler(userData); 350 } 351 352 /** 353 * Returns the JvmMemPoolTable SnmpTableHandler 354 **/ 355 protected SnmpTableHandler getPoolHandler(Object userData) { 356 final JvmMemPoolTableMetaImpl poolTable = getPools(theMib); 357 return poolTable.getHandler(userData); 358 } 359 360 // See com.sun.jmx.snmp.agent.SnmpMibTable 361 protected SnmpOid getNextOid(Object userData) 362 throws SnmpStatusException { 363 // null means get the first OID. 364 return getNextOid(null,userData); 365 } 366 367 // See com.sun.jmx.snmp.agent.SnmpMibTable 368 protected SnmpOid getNextOid(SnmpOid oid, Object userData) 369 throws SnmpStatusException { 370 final boolean dbg = log.isDebugOn(); 371 if (dbg) log.debug("getNextOid", "previous=" + oid); 372 373 374 // Get the data handler. 375 // 376 SnmpTableHandler handler = getHandler(userData); 377 if (handler == null) { 378 // This should never happen. 379 // If we get here it's a bug. 380 // 381 if (dbg) log.debug("getNextOid", "handler is null!"); 382 throw new SnmpStatusException(SnmpStatusException.noSuchInstance); 383 } 384 385 // Get the next oid 386 // 387 final SnmpOid next = handler.getNext(oid); 388 if (dbg) log.debug("getNextOid", "next=" + next); 389 390 // if next is null: we reached the end of the table. 391 // 392 if (next == null) 393 throw new SnmpStatusException(SnmpStatusException.noSuchInstance); 394 395 return next; 396 } 397 398 399 // See com.sun.jmx.snmp.agent.SnmpMibTable 400 protected boolean contains(SnmpOid oid, Object userData) { 401 402 // Get the handler. 403 // 404 SnmpTableHandler handler = getHandler(userData); 405 406 // handler should never be null. 407 // 408 if (handler == null) 409 return false; 410 411 return handler.contains(oid); 412 } 413 414 // See com.sun.jmx.snmp.agent.SnmpMibTable 415 public Object getEntry(SnmpOid oid) 416 throws SnmpStatusException { 417 418 if (oid == null || oid.getLength() < 2) 419 throw new SnmpStatusException(SnmpStatusException.noSuchInstance); 420 421 // Get the request contextual cache (userData). 422 // 423 final Map<Object, Object> m = JvmContextFactory.getUserData(); 424 425 // We know in the case of this table that the index is composed 426 // of two integers, 427 // o The MemoryManager is the first OID arc of the index OID. 428 // o The MemoryPool is the second OID arc of the index OID. 429 // 430 final long mgrIndex = oid.getOidArc(0); 431 final long poolIndex = oid.getOidArc(1); 432 433 // We're going to use this name to store/retrieve the entry in 434 // the request contextual cache. 435 // 436 // Revisit: Probably better programming to put all these strings 437 // in some interface. 438 // 439 final String entryTag = ((m==null)?null: 440 ("JvmMemMgrPoolRelTable.entry." + 441 mgrIndex + "." + poolIndex)); 442 443 // If the entry is in the cache, simply return it. 444 // 445 if (m != null) { 446 final Object entry = m.get(entryTag); 447 if (entry != null) return entry; 448 } 449 450 // The entry was not in the cache, make a new one. 451 // 452 // Get the data hanler. 453 // 454 SnmpTableHandler handler = getHandler(m); 455 456 // handler should never be null. 457 // 458 if (handler == null) 459 throw new SnmpStatusException(SnmpStatusException.noSuchInstance); 460 461 // Get the data associated with our entry. 462 // 463 final Object data = handler.getData(oid); 464 465 // data may be null if the OID we were given is not valid. 466 // 467 if (!(data instanceof JvmMemMgrPoolRelEntryImpl)) 468 throw new SnmpStatusException(SnmpStatusException.noSuchInstance); 469 470 // make the new entry (transient object that will be kept only 471 // for the duration of the request. 472 // 473 final Object entry = (JvmMemMgrPoolRelEntryImpl)data; 474 // XXXXX Revisit 475 // new JvmMemMgrPoolRelEntryImpl((MemoryManagerMXBean)data, 476 // (int)mgrIndex,(int)poolIndex); 477 478 // Put the entry in the cache in case we need it later while processing 479 // the request. 480 // 481 if (m != null && entry != null) { 482 m.put(entryTag,entry); 483 } 484 485 return entry; 486 } 487 488 /** 489 * Get the SnmpTableHandler that holds the jvmMemManagerTable data. 490 * First look it up in the request contextual cache, and if it is 491 * not found, obtain it from the weak cache. 492 * <br>The request contextual cache will be released at the end of the 493 * current requests, and is used only to process this request. 494 * <br>The weak cache is shared by all requests, and is only 495 * recomputed when it is found to be obsolete. 496 * <br>Note that the data put in the request contextual cache is 497 * never considered to be obsolete, in order to preserve data 498 * coherency. 499 **/ 500 protected SnmpTableHandler getHandler(Object userData) { 501 final Map<Object, Object> m; 502 if (userData instanceof Map) m=Util.cast(userData); 503 else m=null; 504 505 // Look in the contextual cache. 506 if (m != null) { 507 final SnmpTableHandler handler = 508 (SnmpTableHandler)m.get("JvmMemMgrPoolRelTable.handler"); 509 if (handler != null) return handler; 510 } 511 512 // No handler in contextual cache, make a new one. 513 final SnmpTableHandler handler = cache.getTableHandler(); 514 515 if (m != null && handler != null ) 516 m.put("JvmMemMgrPoolRelTable.handler",handler); 517 518 return handler; 519 } 520 521 static final MibLogger log = 522 new MibLogger(JvmMemMgrPoolRelTableMetaImpl.class); 523 }