1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.dbi; 9 10 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_ADMIN_BYTES; 11 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_DATA_BYTES; 12 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_DATA_ADMIN_BYTES; 13 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_GROUP_DESC; 14 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_GROUP_NAME; 15 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_LOCK_BYTES; 16 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_SHARED_CACHE_TOTAL_BYTES; 17 import static com.sleepycat.je.dbi.DbiStatDefinition.MB_TOTAL_BYTES; 18 19 import java.lang.management.ManagementFactory; 20 import java.util.List; 21 import java.util.concurrent.atomic.AtomicLong; 22 23 import com.sleepycat.bind.tuple.TupleOutput; 24 import com.sleepycat.je.DatabaseException; 25 import com.sleepycat.je.EnvironmentMutableConfig; 26 import com.sleepycat.je.config.EnvironmentParams; 27 import com.sleepycat.je.tree.IN; 28 import com.sleepycat.je.utilint.LoggerUtils; 29 import com.sleepycat.je.utilint.LongStat; 30 import com.sleepycat.je.utilint.StatGroup; 31 32 /** 33 * MemoryBudget calculates the available memory for JE and how to apportion 34 * it between cache and log buffers. It is meant to centralize all memory 35 * calculations. Objects that ask for memory budgets should get settings from 36 * this class, rather than using the configuration parameter values directly. 37 */ 38 public class MemoryBudget implements EnvConfigObserver { 39 40 /* 41 * CLEANUP_DONE can be set to false for unit test debugging 42 * that is still in progress. When we do the final regression, 43 * this should be removed to be assured that it is never false. 44 */ 45 public static boolean CLEANUP_DONE = false; 46 47 /* 48 * These DEBUG variables are public so unit tests can easily turn them 49 * on and off for different sections of code. 50 */ 51 public static boolean DEBUG_ADMIN = Boolean.getBoolean("memAdmin"); 52 public static boolean DEBUG_LOCK = Boolean.getBoolean("memLock"); 53 public static boolean DEBUG_TXN = Boolean.getBoolean("memTxn"); 54 public static boolean DEBUG_TREEADMIN = Boolean.getBoolean("memTreeAdmin"); 55 public static boolean DEBUG_TREE = Boolean.getBoolean("memTree"); 56 57 /* 58 * Object overheads. These are set statically with advance measurements. 59 * Java doesn't provide a way of assessing object size dynamically. These 60 * overheads will not be precise, but are close enough to let the system 61 * behave predictably. 62 * 63 * _32 values are the same on Windows and Solaris. 64 * _64 values are from Linux (were previously 1.5.0_05 on Solaris). 65 * _OOPS are on a 64b JVM with -XX:+UseCompressedOops 66 * 67 * The integer following the // below is the Sizeof argument used to 68 * compute the value. 69 */ 70 71 // 7 72 private final static int LONG_OVERHEAD_32 = 16; 73 private final static int LONG_OVERHEAD_64 = 24; 74 private final static int LONG_OVERHEAD_OOPS = 24; 75 76 // 8 77 private final static int ARRAY_OVERHEAD_32 = 16; 78 private final static int ARRAY_OVERHEAD_64 = 24; 79 private final static int ARRAY_OVERHEAD_OOPS = 16; 80 81 // see byteArraySize 82 private final static int ARRAY_SIZE_INCLUDED_32 = 4; 83 private final static int ARRAY_SIZE_INCLUDED_64 = 0; 84 private final static int ARRAY_SIZE_INCLUDED_OOPS = 0; 85 86 // 2 87 private final static int OBJECT_OVERHEAD_32 = 8; 88 private final static int OBJECT_OVERHEAD_64 = 16; 89 private final static int OBJECT_OVERHEAD_OOPS = 16; 90 91 // (4 - ARRAY_OVERHEAD) / 256 92 // 32b: 4 is 1040 93 // 64b: 4 is 2078 94 // Oops: 4 is 1040 95 private final static int OBJECT_ARRAY_ITEM_OVERHEAD_32 = 4; 96 private final static int OBJECT_ARRAY_ITEM_OVERHEAD_64 = 8; 97 private final static int OBJECT_ARRAY_ITEM_OVERHEAD_OOPS = 4; 98 99 // 20 100 private final static int HASHMAP_OVERHEAD_32 = 120; 101 private final static int HASHMAP_OVERHEAD_64 = 219; 102 private final static int HASHMAP_OVERHEAD_OOPS = 128; 103 104 // 21 - OBJECT_OVERHEAD - HASHMAP_OVERHEAD 105 // 32b: 21 is 152 106 // 64b: 21 is max(280,...,287) on Linux/Solaris 1.5/1.6 107 // Oops: 21 is 176 108 private final static int HASHMAP_ENTRY_OVERHEAD_32 = 24; 109 private final static int HASHMAP_ENTRY_OVERHEAD_64 = 52; 110 private final static int HASHMAP_ENTRY_OVERHEAD_OOPS = 32; 111 112 // 22 113 private final static int HASHSET_OVERHEAD_32 = 136; 114 private final static int HASHSET_OVERHEAD_64 = 240; 115 private final static int HASHSET_OVERHEAD_OOPS = 144; 116 117 // 23 - OBJECT_OVERHEAD - HASHSET_OVERHEAD 118 // 32b: 23 is 168 119 // 64b: 23 is max(304,...,311) on Linux/Solaris 120 // Oops: 23 is 192 121 private final static int HASHSET_ENTRY_OVERHEAD_32 = 24; 122 private final static int HASHSET_ENTRY_OVERHEAD_64 = 55; 123 private final static int HASHSET_ENTRY_OVERHEAD_OOPS = 32; 124 125 // HASHMAP_OVERHEAD * 2 126 private final static int TWOHASHMAPS_OVERHEAD_32 = 240; 127 private final static int TWOHASHMAPS_OVERHEAD_64 = 438; 128 private final static int TWOHASHMAPS_OVERHEAD_OOPS = 256; 129 130 // 34 131 private final static int TREEMAP_OVERHEAD_32 = 48; 132 private final static int TREEMAP_OVERHEAD_64 = 80; 133 private final static int TREEMAP_OVERHEAD_OOPS = 48; 134 135 // 35 - OBJECT_OVERHEAD - TREEMAP_OVERHEAD 136 // 32b: 35 is 88 137 // 64b: 35 is 160 138 // Oops: 35 is 104 139 private final static int TREEMAP_ENTRY_OVERHEAD_32 = 32; 140 private final static int TREEMAP_ENTRY_OVERHEAD_64 = 64; 141 private final static int TREEMAP_ENTRY_OVERHEAD_OOPS = 40; 142 143 // 36 144 // 32b JDK 1.7 is 928 145 private final static int MAPLN_OVERHEAD_32 = 920; 146 private final static int MAPLN_OVERHEAD_64 = 1624; 147 private final static int MAPLN_OVERHEAD_OOPS = 1016; 148 149 // 9 150 private final static int LN_OVERHEAD_32 = 16; 151 private final static int LN_OVERHEAD_64 = 32; 152 private final static int LN_OVERHEAD_OOPS = 24; 153 154 // 17 minus 9 155 // 32b: 17 is 24 156 // 64b: 17 is 40 157 // Oops: 17 is 32 158 private final static int VERSIONEDLN_OVERHEAD_32 = 8; 159 private final static int VERSIONEDLN_OVERHEAD_64 = 8; 160 private final static int VERSIONEDLN_OVERHEAD_OOPS = 8; 161 162 // No longer updated, as dups are no longer used except during conversion. 163 private final static int DUPCOUNTLN_OVERHEAD_32 = 32; 164 private final static int DUPCOUNTLN_OVERHEAD_64 = 48; 165 private final static int DUPCOUNTLN_OVERHEAD_OOPS = 40; 166 167 // 12 168 private final static int BIN_FIXED_OVERHEAD_32 = 208; 169 private final static int BIN_FIXED_OVERHEAD_64 = 328; 170 private final static int BIN_FIXED_OVERHEAD_OOPS = 224; 171 172 // 18 173 private final static int BINDELTA_OVERHEAD_32 = 48; 174 private final static int BINDELTA_OVERHEAD_64 = 72; 175 private final static int BINDELTA_OVERHEAD_OOPS = 64; 176 177 // 19 178 private final static int DELTAINFO_OVERHEAD_32 = 24; 179 private final static int DELTAINFO_OVERHEAD_64 = 40; 180 private final static int DELTAINFO_OVERHEAD_OOPS = 32; 181 182 // 47 183 private final static int SPARSE_TARGET_ENTRY_OVERHEAD_32 = 72; 184 private final static int SPARSE_TARGET_ENTRY_OVERHEAD_64 = 120; 185 private final static int SPARSE_TARGET_ENTRY_OVERHEAD_OOPS = 80; 186 187 // 48 188 private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_32 = 16; 189 private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_64 = 24; 190 private final static int DEFAULT_TARGET_ENTRY_OVERHEAD_OOPS = 16; 191 192 // 49 193 private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_32 = 16; 194 private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_64 = 32; 195 private final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD_OOPS = 24; 196 197 // 50 198 private final static int DEFAULT_KEYVALS_OVERHEAD_32 = 16; 199 private final static int DEFAULT_KEYVALS_OVERHEAD_64 = 24; 200 private final static int DEFAULT_KEYVALS_OVERHEAD_OOPS = 16; 201 202 // 52 203 private final static int DEFAULT_LONG_REP_OVERHEAD_32 = 16; 204 private final static int DEFAULT_LONG_REP_OVERHEAD_64 = 32; 205 private final static int DEFAULT_LONG_REP_OVERHEAD_OOPS = 24; 206 207 // 54 208 private final static int DIN_FIXED_OVERHEAD_32 = 120; 209 private final static int DIN_FIXED_OVERHEAD_64 = 176; 210 private final static int DIN_FIXED_OVERHEAD_OOPS = 120; 211 212 // 53 213 private final static int DBIN_FIXED_OVERHEAD_32 = 152; 214 private final static int DBIN_FIXED_OVERHEAD_64 = 232; 215 private final static int DBIN_FIXED_OVERHEAD_OOPS = 168; 216 217 // 13 218 private final static int IN_FIXED_OVERHEAD_32 = 296; 219 private final static int IN_FIXED_OVERHEAD_64 = 392; 220 private final static int IN_FIXED_OVERHEAD_OOPS = 256; 221 222 // 6 223 private final static int KEY_OVERHEAD_32 = 16; 224 private final static int KEY_OVERHEAD_64 = 24; 225 private final static int KEY_OVERHEAD_OOPS = 16; 226 227 // 24 228 private final static int LOCKIMPL_OVERHEAD_32 = 24; 229 private final static int LOCKIMPL_OVERHEAD_64 = 48; 230 private final static int LOCKIMPL_OVERHEAD_OOPS = 32; 231 232 // 42 233 private final static int THINLOCKIMPL_OVERHEAD_32 = 16; 234 private final static int THINLOCKIMPL_OVERHEAD_64 = 32; 235 private final static int THINLOCKIMPL_OVERHEAD_OOPS = 24; 236 237 // 25 238 private final static int LOCKINFO_OVERHEAD_32 = 16; 239 private final static int LOCKINFO_OVERHEAD_64 = 32; 240 private final static int LOCKINFO_OVERHEAD_OOPS = 24; 241 242 // 37 243 private final static int WRITE_LOCKINFO_OVERHEAD_32 = 32; 244 private final static int WRITE_LOCKINFO_OVERHEAD_64 = 40; 245 private final static int WRITE_LOCKINFO_OVERHEAD_OOPS = 32; 246 247 /* 248 * Txn memory is the size for the Txn + a hashmap entry 249 * overhead for being part of the transaction table. 250 */ 251 // 15 252 private final static int TXN_OVERHEAD_32 = 224; 253 private final static int TXN_OVERHEAD_64 = 353; 254 private final static int TXN_OVERHEAD_OOPS = 232; 255 256 // 26 257 private final static int CHECKPOINT_REFERENCE_SIZE_32 = 32 + 258 HASHSET_ENTRY_OVERHEAD_32; 259 private final static int CHECKPOINT_REFERENCE_SIZE_64 = 48 + 260 HASHSET_ENTRY_OVERHEAD_64; 261 private final static int CHECKPOINT_REFERENCE_SIZE_OOPS = 32 + 262 HASHSET_ENTRY_OVERHEAD_OOPS; 263 264 /* The per-log-file bytes used in UtilizationProfile. */ 265 // 29 / 10.0 (That is the number 10, not the Sizeof type 10) 266 // 32b: 29 is 1088 267 // 64b: 29 is 1605 268 // Oops: 29 is 1248 269 private final static int UTILIZATION_PROFILE_ENTRY_32 = 109; 270 private final static int UTILIZATION_PROFILE_ENTRY_64 = 161; 271 private final static int UTILIZATION_PROFILE_ENTRY_OOPS = 125; 272 273 // 38 274 private final static int DBFILESUMMARY_OVERHEAD_32 = 40; 275 private final static int DBFILESUMMARY_OVERHEAD_64 = 48; 276 private final static int DBFILESUMMARY_OVERHEAD_OOPS = 48; 277 278 /* Tracked File Summary overheads. */ 279 // 31 280 private final static int TFS_LIST_INITIAL_OVERHEAD_32 = 464; 281 private final static int TFS_LIST_INITIAL_OVERHEAD_64 = 504; 282 private final static int TFS_LIST_INITIAL_OVERHEAD_OOPS = 464; 283 284 // 30 285 // 64b: 30 is max(464,464,464,465) on Linux/Solaris on 1.5/1.6 286 private final static int TFS_LIST_SEGMENT_OVERHEAD_32 = 440; 287 private final static int TFS_LIST_SEGMENT_OVERHEAD_64 = 465; 288 private final static int TFS_LIST_SEGMENT_OVERHEAD_OOPS = 440; 289 290 // 33 291 private final static int LN_INFO_OVERHEAD_32 = 24; 292 private final static int LN_INFO_OVERHEAD_64 = 40; 293 private final static int LN_INFO_OVERHEAD_OOPS = 24; 294 295 // 43 296 private final static int FILESUMMARYLN_OVERHEAD_32 = 112; 297 private final static int FILESUMMARYLN_OVERHEAD_64 = 168; 298 private final static int FILESUMMARYLN_OVERHEAD_OOPS = 128; 299 300 // 51 301 private final static int INENTRY_OVERHEAD_32 = 16; 302 private final static int INENTRY_OVERHEAD_64 = 32; 303 private final static int INENTRY_OVERHEAD_OOPS= 24; 304 305 // 46 306 private final static int DELTAINENTRY_OVERHEAD_32 = 32; 307 private final static int DELTAINENTRY_OVERHEAD_64 = 48; 308 private final static int DELTAINENTRY_OVERHEAD_OOPS= 32; 309 310 // 27 minus zero length Object array 311 private final static int EMPTY_OBJ_ARRAY = objectArraySize(0); 312 private final static int ARRAYLIST_OVERHEAD_32 = 40 - EMPTY_OBJ_ARRAY; 313 private final static int ARRAYLIST_OVERHEAD_64 = 64 - EMPTY_OBJ_ARRAY; 314 private final static int ARRAYLIST_OVERHEAD_OOPS = 40 - EMPTY_OBJ_ARRAY; 315 316 // 44 minus 45 317 // 32b: 44 and 45 are 40 and 16, resp. 318 // 64b: 44 and 45 are 56 and 24, resp. 319 // Oops: 44 and 45 are 40 and 16, resp. 320 private final static int TUPLE_OUTPUT_OVERHEAD_32 = 24; 321 private final static int TUPLE_OUTPUT_OVERHEAD_64 = 32; 322 private final static int TUPLE_OUTPUT_OVERHEAD_OOPS = 24; 323 324 public final static int LONG_OVERHEAD; 325 public final static int ARRAY_OVERHEAD; 326 public final static int ARRAY_SIZE_INCLUDED; 327 public final static int OBJECT_OVERHEAD; 328 public final static int OBJECT_ARRAY_ITEM_OVERHEAD; 329 public final static int HASHMAP_OVERHEAD; 330 public final static int HASHMAP_ENTRY_OVERHEAD; 331 public final static int HASHSET_OVERHEAD; 332 public final static int HASHSET_ENTRY_OVERHEAD; 333 public final static int TWOHASHMAPS_OVERHEAD; 334 public final static int TREEMAP_OVERHEAD; 335 public final static int TREEMAP_ENTRY_OVERHEAD; 336 public final static int MAPLN_OVERHEAD; 337 public final static int LN_OVERHEAD; 338 public final static int VERSIONEDLN_OVERHEAD; 339 public final static int DUPCOUNTLN_OVERHEAD; 340 public final static int BIN_FIXED_OVERHEAD; 341 public final static int BINDELTA_OVERHEAD; 342 public final static int DELTAINFO_OVERHEAD; 343 public final static int SPARSE_TARGET_ENTRY_OVERHEAD; 344 public final static int DEFAULT_TARGET_ENTRY_OVERHEAD; 345 public final static int DEFAULT_KEYVALS_OVERHEAD; 346 public final static int MAX_KEY_SIZE_KEYVALS_OVERHEAD; 347 public final static int DEFAULT_LONG_REP_OVERHEAD; 348 public final static int DIN_FIXED_OVERHEAD; 349 public final static int DBIN_FIXED_OVERHEAD; 350 public final static int IN_FIXED_OVERHEAD; 351 public final static int KEY_OVERHEAD; 352 public final static int LOCKIMPL_OVERHEAD; 353 public final static int THINLOCKIMPL_OVERHEAD; 354 public final static int LOCKINFO_OVERHEAD; 355 public final static int WRITE_LOCKINFO_OVERHEAD; 356 public final static int TXN_OVERHEAD; 357 public final static int CHECKPOINT_REFERENCE_SIZE; 358 public final static int UTILIZATION_PROFILE_ENTRY; 359 public final static int DBFILESUMMARY_OVERHEAD; 360 public final static int TFS_LIST_INITIAL_OVERHEAD; 361 public final static int TFS_LIST_SEGMENT_OVERHEAD; 362 public final static int LN_INFO_OVERHEAD; 363 public final static int FILESUMMARYLN_OVERHEAD; 364 public final static int INENTRY_OVERHEAD; 365 public final static int DELTAINENTRY_OVERHEAD; 366 public final static int ARRAYLIST_OVERHEAD; 367 public final static int TUPLE_OUTPUT_OVERHEAD; 368 369 /* Primitive long array item size is the same on all platforms. */ 370 public final static int PRIMITIVE_LONG_ARRAY_ITEM_OVERHEAD = 8; 371 372 private final static String JVM_ARCH_PROPERTY = "sun.arch.data.model"; 373 private final static String FORCE_JVM_ARCH = "je.forceJVMArch"; 374 private static boolean COMPRESSED_OOPS_REQUESTED = false; 375 private static boolean COMPRESSED_OOPS_KNOWN = false; 376 private static boolean COMPRESSED_OOPS_KNOWN_ON = false; 377 378 static { 379 String javaVersion = System.getProperty("java.version"); 380 boolean is64 = false; 381 String overrideArch = System.getProperty(FORCE_JVM_ARCH); 382 383 try { 384 if (overrideArch == null) { 385 String arch = System.getProperty(JVM_ARCH_PROPERTY); 386 if (arch != null) { 387 is64 = Integer.parseInt(arch) == 64; 388 } 389 } else { 390 is64 = Integer.parseInt(overrideArch) == 64; 391 } 392 } catch (NumberFormatException NFE) { 393 NFE.printStackTrace(System.err); 394 } 395 396 final Boolean checkCompressedOops = 397 CompressedOopsDetector.isEnabled(); 398 if (checkCompressedOops != null) { 399 COMPRESSED_OOPS_KNOWN = true; 400 COMPRESSED_OOPS_KNOWN_ON = checkCompressedOops; 401 } 402 403 //ONEJAVA/* 404 List<String> args = 405 ManagementFactory.getRuntimeMXBean().getInputArguments(); 406 for (String arg : args) { 407 if ("-XX:+UseCompressedOops".equals(arg)) { 408 COMPRESSED_OOPS_REQUESTED = true; 409 break; 410 } 411 } 412 //ONEJAVA*/ 413 414 final boolean useCompressedOops = COMPRESSED_OOPS_KNOWN ? 415 COMPRESSED_OOPS_KNOWN_ON : 416 COMPRESSED_OOPS_REQUESTED; 417 418 if (useCompressedOops) { 419 LONG_OVERHEAD = LONG_OVERHEAD_OOPS; 420 ARRAY_OVERHEAD = ARRAY_OVERHEAD_OOPS; 421 ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_OOPS; 422 OBJECT_OVERHEAD = OBJECT_OVERHEAD_OOPS; 423 OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_OOPS; 424 HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_OOPS; 425 HASHSET_OVERHEAD = HASHSET_OVERHEAD_OOPS; 426 HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_OOPS; 427 TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_OOPS; 428 MAPLN_OVERHEAD = MAPLN_OVERHEAD_OOPS; 429 BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_OOPS; 430 BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_OOPS; 431 DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_OOPS; 432 SPARSE_TARGET_ENTRY_OVERHEAD = 433 SPARSE_TARGET_ENTRY_OVERHEAD_OOPS; 434 DEFAULT_TARGET_ENTRY_OVERHEAD = 435 DEFAULT_TARGET_ENTRY_OVERHEAD_OOPS; 436 DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_OOPS; 437 MAX_KEY_SIZE_KEYVALS_OVERHEAD = 438 MAX_KEY_SIZE_KEYVALS_OVERHEAD_OOPS; 439 DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_OOPS; 440 DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_OOPS; 441 DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_OOPS; 442 IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_OOPS; 443 HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_OOPS; 444 TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_OOPS; 445 TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_OOPS; 446 LN_OVERHEAD = LN_OVERHEAD_OOPS; 447 VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_OOPS; 448 DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_OOPS; 449 TXN_OVERHEAD = TXN_OVERHEAD_OOPS; 450 CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_OOPS; 451 KEY_OVERHEAD = KEY_OVERHEAD_OOPS; 452 LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_OOPS; 453 THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_OOPS; 454 LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_OOPS; 455 WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_OOPS; 456 UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_OOPS; 457 DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_OOPS; 458 TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_OOPS; 459 TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_OOPS; 460 LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_OOPS; 461 FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_OOPS; 462 INENTRY_OVERHEAD = INENTRY_OVERHEAD_OOPS; 463 DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_OOPS; 464 ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_OOPS; 465 TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_OOPS; 466 } else if (is64) { 467 LONG_OVERHEAD = LONG_OVERHEAD_64; 468 ARRAY_OVERHEAD = ARRAY_OVERHEAD_64; 469 ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_64; 470 OBJECT_OVERHEAD = OBJECT_OVERHEAD_64; 471 OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_64; 472 HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_64; 473 HASHSET_OVERHEAD = HASHSET_OVERHEAD_64; 474 HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_64; 475 TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_64; 476 MAPLN_OVERHEAD = MAPLN_OVERHEAD_64; 477 BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_64; 478 DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_64; 479 DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_64; 480 IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_64; 481 HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_64; 482 TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_64; 483 BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_64; 484 DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_64; 485 SPARSE_TARGET_ENTRY_OVERHEAD = SPARSE_TARGET_ENTRY_OVERHEAD_64; 486 DEFAULT_TARGET_ENTRY_OVERHEAD = 487 DEFAULT_TARGET_ENTRY_OVERHEAD_64; 488 DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_64; 489 MAX_KEY_SIZE_KEYVALS_OVERHEAD = 490 MAX_KEY_SIZE_KEYVALS_OVERHEAD_64; 491 DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_64; 492 TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_64; 493 LN_OVERHEAD = LN_OVERHEAD_64; 494 VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_64; 495 DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_64; 496 TXN_OVERHEAD = TXN_OVERHEAD_64; 497 CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_64; 498 KEY_OVERHEAD = KEY_OVERHEAD_64; 499 LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_64; 500 THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_64; 501 LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_64; 502 WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_64; 503 UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_64; 504 DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_64; 505 TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_64; 506 TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_64; 507 LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_64; 508 FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_64; 509 INENTRY_OVERHEAD = INENTRY_OVERHEAD_64; 510 DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_64; 511 ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_64; 512 TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_64; 513 } else { 514 LONG_OVERHEAD = LONG_OVERHEAD_32; 515 ARRAY_OVERHEAD = ARRAY_OVERHEAD_32; 516 ARRAY_SIZE_INCLUDED = ARRAY_SIZE_INCLUDED_32; 517 OBJECT_OVERHEAD = OBJECT_OVERHEAD_32; 518 OBJECT_ARRAY_ITEM_OVERHEAD = OBJECT_ARRAY_ITEM_OVERHEAD_32; 519 HASHMAP_OVERHEAD = HASHMAP_OVERHEAD_32; 520 HASHMAP_ENTRY_OVERHEAD = HASHMAP_ENTRY_OVERHEAD_32; 521 HASHSET_OVERHEAD = HASHSET_OVERHEAD_32; 522 HASHSET_ENTRY_OVERHEAD = HASHSET_ENTRY_OVERHEAD_32; 523 TWOHASHMAPS_OVERHEAD = TWOHASHMAPS_OVERHEAD_32; 524 TREEMAP_OVERHEAD = TREEMAP_OVERHEAD_32; 525 MAPLN_OVERHEAD = MAPLN_OVERHEAD_32; 526 TREEMAP_ENTRY_OVERHEAD = TREEMAP_ENTRY_OVERHEAD_32; 527 LN_OVERHEAD = LN_OVERHEAD_32; 528 VERSIONEDLN_OVERHEAD = VERSIONEDLN_OVERHEAD_32; 529 DUPCOUNTLN_OVERHEAD = DUPCOUNTLN_OVERHEAD_32; 530 BIN_FIXED_OVERHEAD = BIN_FIXED_OVERHEAD_32; 531 BINDELTA_OVERHEAD = BINDELTA_OVERHEAD_32; 532 DELTAINFO_OVERHEAD = DELTAINFO_OVERHEAD_32; 533 SPARSE_TARGET_ENTRY_OVERHEAD = SPARSE_TARGET_ENTRY_OVERHEAD_32; 534 DEFAULT_TARGET_ENTRY_OVERHEAD = 535 DEFAULT_TARGET_ENTRY_OVERHEAD_32; 536 DEFAULT_KEYVALS_OVERHEAD = DEFAULT_KEYVALS_OVERHEAD_32; 537 MAX_KEY_SIZE_KEYVALS_OVERHEAD = 538 MAX_KEY_SIZE_KEYVALS_OVERHEAD_32; 539 DEFAULT_LONG_REP_OVERHEAD = DEFAULT_LONG_REP_OVERHEAD_32; 540 DIN_FIXED_OVERHEAD = DIN_FIXED_OVERHEAD_32; 541 DBIN_FIXED_OVERHEAD = DBIN_FIXED_OVERHEAD_32; 542 IN_FIXED_OVERHEAD = IN_FIXED_OVERHEAD_32; 543 TXN_OVERHEAD = TXN_OVERHEAD_32; 544 CHECKPOINT_REFERENCE_SIZE = CHECKPOINT_REFERENCE_SIZE_32; 545 KEY_OVERHEAD = KEY_OVERHEAD_32; 546 LOCKIMPL_OVERHEAD = LOCKIMPL_OVERHEAD_32; 547 THINLOCKIMPL_OVERHEAD = THINLOCKIMPL_OVERHEAD_32; 548 LOCKINFO_OVERHEAD = LOCKINFO_OVERHEAD_32; 549 WRITE_LOCKINFO_OVERHEAD = WRITE_LOCKINFO_OVERHEAD_32; 550 UTILIZATION_PROFILE_ENTRY = UTILIZATION_PROFILE_ENTRY_32; 551 DBFILESUMMARY_OVERHEAD = DBFILESUMMARY_OVERHEAD_32; 552 TFS_LIST_INITIAL_OVERHEAD = TFS_LIST_INITIAL_OVERHEAD_32; 553 TFS_LIST_SEGMENT_OVERHEAD = TFS_LIST_SEGMENT_OVERHEAD_32; 554 LN_INFO_OVERHEAD = LN_INFO_OVERHEAD_32; 555 FILESUMMARYLN_OVERHEAD = FILESUMMARYLN_OVERHEAD_32; 556 INENTRY_OVERHEAD = INENTRY_OVERHEAD_32; 557 DELTAINENTRY_OVERHEAD = DELTAINENTRY_OVERHEAD_32; 558 ARRAYLIST_OVERHEAD = ARRAYLIST_OVERHEAD_32; 559 TUPLE_OUTPUT_OVERHEAD = TUPLE_OUTPUT_OVERHEAD_32; 560 } 561 } 562 563 /* public for unit tests. */ 564 public final static long MIN_MAX_MEMORY_SIZE = 96 * 1024; 565 public final static String MIN_MAX_MEMORY_SIZE_STRING = 566 Long.toString(MIN_MAX_MEMORY_SIZE); 567 568 /* This value prevents cache churn for apps with a high write rate. */ 569 @SuppressWarnings("unused") 570 private final static int DEFAULT_MIN_BTREE_CACHE_SIZE = 500 * 1024; 571 572 private final static long N_64MB = (1 << 26); 573 574 /* 575 * Note that this class contains long fields that are accessed by multiple 576 * threads. Access to these fields is synchronized when changing them but 577 * not when reading them to detect cache overflow or get stats. Although 578 * inaccuracies may occur when reading the values, correcting this is not 579 * worth the cost of synchronizing every time we access them. The worst 580 * that can happen is that we may invoke eviction unnecessarily. 581 */ 582 583 /* 584 * Amount of memory cached for tree objects. 585 */ 586 private final AtomicLong treeMemoryUsage = new AtomicLong(0); 587 588 /* 589 * Amount of memory cached for txn usage. 590 */ 591 private final AtomicLong txnMemoryUsage = new AtomicLong(0); 592 593 /* 594 * Amount of memory cached for log cleaning, dirty IN list, and other admin 595 * functions. 596 */ 597 private final AtomicLong adminMemoryUsage = new AtomicLong(0); 598 599 /* 600 * Amount of memory cached for admininstrative structures that are 601 * sometimes housed within tree nodes. Right now, that's 602 * DbFileSummaryMap, which is sometimes referenced by a MapLN by 603 * way of a DatabaseImpl, and sometimes is just referenced by 604 * a DatabaseImpl without a MapLN (the id and name databases.) 605 */ 606 private final AtomicLong treeAdminMemoryUsage = new AtomicLong(0); 607 608 /* 609 * Amount of memory cached for locks. Protected by the 610 * LockManager.lockTableLatches[lockTableIndex]. 611 */ 612 private final AtomicLong lockMemoryUsage = new AtomicLong(0); 613 614 /* 615 * Memory available to JE, based on je.maxMemory and the memory available 616 * to this process. 617 */ 618 private final Totals totals; 619 620 /* Memory available to log buffers. */ 621 private long logBufferBudget; 622 623 /* Maximum allowed use of the admin budget by the UtilizationTracker. */ 624 private long trackerBudget; 625 626 /* Mininum to prevent cache churn. */ 627 private long minTreeMemoryUsage; 628 629 private final EnvironmentImpl envImpl; 630 MemoryBudget(EnvironmentImpl envImpl, EnvironmentImpl sharedCacheEnv, DbConfigManager configManager)631 MemoryBudget(EnvironmentImpl envImpl, 632 EnvironmentImpl sharedCacheEnv, 633 DbConfigManager configManager) 634 throws DatabaseException { 635 636 this.envImpl = envImpl; 637 638 /* Request notification of mutable property changes. */ 639 envImpl.addConfigObserver(this); 640 641 /* Perform first time budget initialization. */ 642 long newMaxMemory; 643 if (envImpl.getSharedCache()) { 644 if (sharedCacheEnv != null) { 645 totals = sharedCacheEnv.getMemoryBudget().totals; 646 /* For a new environment, do not override existing budget. */ 647 newMaxMemory = -1; 648 } else { 649 totals = new SharedTotals(); 650 newMaxMemory = calcMaxMemory(configManager); 651 } 652 } else { 653 totals = new PrivateTotals(this); 654 newMaxMemory = calcMaxMemory(configManager); 655 } 656 reset(newMaxMemory, true /*newEnv*/, configManager); 657 658 checkCompressedOops(); 659 } 660 661 /** 662 * Logs a SEVERE message if compressed oops was specified but did not take 663 * effect. Must be called after the environment is initialized so the 664 * message makes it to the output file. 665 */ checkCompressedOops()666 private void checkCompressedOops() { 667 if (COMPRESSED_OOPS_REQUESTED && 668 COMPRESSED_OOPS_KNOWN && 669 !COMPRESSED_OOPS_KNOWN_ON) { 670 LoggerUtils.severe(envImpl.getLogger(), envImpl, 671 "-XX:+UseCompressedOops was specified but is not in effect," + 672 " probably because the heap size is too large for this JVM" + 673 " option on this platform. This is likely to cause an" + 674 " OutOfMemoryError!"); 675 } 676 } 677 678 /** 679 * Respond to config updates. 680 */ envConfigUpdate(DbConfigManager configManager, EnvironmentMutableConfig ignore)681 public void envConfigUpdate(DbConfigManager configManager, 682 EnvironmentMutableConfig ignore) 683 throws DatabaseException { 684 685 /* Reinitialize the cache budget and the log buffer pool. */ 686 reset(calcMaxMemory(configManager), false /*newEnv*/, configManager); 687 } 688 689 /** 690 * @throws IllegalArgumentException via Environment ctor and 691 * setMutableConfig. 692 */ calcMaxMemory(DbConfigManager configManager)693 private long calcMaxMemory(DbConfigManager configManager) { 694 695 /* 696 * Calculate the total memory allotted to JE. 697 * 1. If je.maxMemory is specified, use that. Check that it's not more 698 * than the JVM memory. 699 * 2. Otherwise, take je.maxMemoryPercent * JVM max memory. 700 */ 701 long newMaxMemory = 702 configManager.getLong(EnvironmentParams.MAX_MEMORY); 703 long jvmMemory = getRuntimeMaxMemory(); 704 705 if (newMaxMemory != 0) { 706 /* Application specified a cache size number, validate it. */ 707 if (jvmMemory < newMaxMemory) { 708 throw new IllegalArgumentException 709 (EnvironmentParams.MAX_MEMORY.getName() + 710 " has a value of " + newMaxMemory + 711 " but the JVM is only configured for " + 712 jvmMemory + 713 ". Consider using je.maxMemoryPercent."); 714 } 715 if (newMaxMemory < MIN_MAX_MEMORY_SIZE) { 716 throw new IllegalArgumentException 717 (EnvironmentParams.MAX_MEMORY.getName() + 718 " is " + newMaxMemory + 719 " which is less than the minimum: " + 720 MIN_MAX_MEMORY_SIZE); 721 } 722 } else { 723 724 /* 725 * When no explicit cache size is specified and the JVM memory size 726 * is unknown, assume a default sized (64 MB) heap. This produces 727 * a reasonable cache size when no heap size is known. 728 */ 729 if (jvmMemory == Long.MAX_VALUE) { 730 jvmMemory = N_64MB; 731 } 732 733 /* Use the configured percentage of the JVM memory size. */ 734 int maxMemoryPercent = 735 configManager.getInt(EnvironmentParams.MAX_MEMORY_PERCENT); 736 newMaxMemory = (maxMemoryPercent * jvmMemory) / 100; 737 } 738 739 return newMaxMemory; 740 } 741 742 /** 743 * Initialize at construction time and when the cache is resized. 744 * 745 * @param newMaxMemory is the new total cache budget or is less than 0 if 746 * the total should remain unchanged. 747 * 748 * @param newEnv is true if this is the first time we are resetting the 749 * budget for a new environment. Note that a new environment has not yet 750 * been added to the set of shared cache environments. 751 */ reset(long newMaxMemory, boolean newEnv, DbConfigManager configManager)752 void reset(long newMaxMemory, 753 boolean newEnv, 754 DbConfigManager configManager) 755 throws DatabaseException { 756 757 long oldLogBufferBudget = logBufferBudget; 758 759 /* 760 * Update the new total cache budget. 761 */ 762 if (newMaxMemory < 0) { 763 newMaxMemory = getMaxMemory(); 764 } else { 765 totals.setMaxMemory(newMaxMemory); 766 } 767 768 /* 769 * This environment's portion is adjusted for a shared cache. Further 770 * below we make buffer and tracker sizes a fixed percentage (7% and 771 * 2%, by default) of the total shared cache size. The math for this 772 * starts by dividing the total size by number of environments to get 773 * myCachePortion. Then we take 7% or 2% of myCachePortion to get each 774 * environment's portion. In other words, if there are 10 environments 775 * then each gets 7%/10 and 2%/10 of the total cache size, by default. 776 * 777 * Note that when we resize the shared cache, we resize the buffer 778 * pools and tracker budgets for all environments. Resizing the 779 * tracker budget has no overhead, but resizing the buffer pools causes 780 * new buffers to be allocated. If reallocation of the log buffers is 781 * not desirable, the user can configure a byte amount rather than a 782 * percentage. 783 */ 784 long myCachePortion; 785 if (envImpl.getSharedCache()) { 786 int nEnvs = DbEnvPool.getInstance().getNSharedCacheEnvironments(); 787 if (newEnv) { 788 nEnvs += 1; 789 } 790 myCachePortion = newMaxMemory / nEnvs; 791 } else { 792 myCachePortion = newMaxMemory; 793 } 794 795 /* 796 * Calculate the memory budget for log buffering. If the LOG_MEM_SIZE 797 * parameter is not set, start by using 7% (1/16th) of the cache 798 * size. If it is set, use that explicit setting. 799 * 800 * No point in having more log buffers than the maximum size. If 801 * this starting point results in overly large log buffers, 802 * reduce the log buffer budget again. 803 */ 804 long newLogBufferBudget = 805 configManager.getLong(EnvironmentParams.LOG_MEM_SIZE); 806 if (newLogBufferBudget == 0) { 807 newLogBufferBudget = myCachePortion >> 4; 808 } else if (newLogBufferBudget > myCachePortion / 2) { 809 newLogBufferBudget = myCachePortion / 2; 810 } 811 812 /* 813 * We have a first pass at the log buffer budget. See what 814 * size log buffers result. Don't let them be too big, it would 815 * be a waste. 816 */ 817 int numBuffers = 818 configManager.getInt(EnvironmentParams.NUM_LOG_BUFFERS); 819 long startingBufferSize = newLogBufferBudget / numBuffers; 820 int logBufferSize = 821 configManager.getInt(EnvironmentParams.LOG_BUFFER_MAX_SIZE); 822 if (startingBufferSize > logBufferSize) { 823 startingBufferSize = logBufferSize; 824 newLogBufferBudget = numBuffers * startingBufferSize; 825 } else if (startingBufferSize < 826 EnvironmentParams.MIN_LOG_BUFFER_SIZE) { 827 startingBufferSize = EnvironmentParams.MIN_LOG_BUFFER_SIZE; 828 newLogBufferBudget = numBuffers * startingBufferSize; 829 } 830 831 long newCriticalThreshold = 832 (newMaxMemory * 833 envImpl.getConfigManager().getInt 834 (EnvironmentParams.EVICTOR_CRITICAL_PERCENTAGE))/100; 835 836 long newTrackerBudget = 837 (myCachePortion * 838 envImpl.getConfigManager().getInt 839 (EnvironmentParams.CLEANER_DETAIL_MAX_MEMORY_PERCENTAGE))/100; 840 841 long newMinTreeMemoryUsage = Math.min 842 (configManager.getLong(EnvironmentParams.MIN_TREE_MEMORY), 843 myCachePortion - newLogBufferBudget); 844 845 /* 846 * If all has gone well, update the budget fields. Once the log buffer 847 * budget is determined, the remainder of the memory is left for tree 848 * nodes. 849 */ 850 logBufferBudget = newLogBufferBudget; 851 totals.setCriticalThreshold(newCriticalThreshold); 852 trackerBudget = newTrackerBudget; 853 minTreeMemoryUsage = newMinTreeMemoryUsage; 854 855 /* The log buffer budget is counted in the cache usage. */ 856 totals.updateCacheUsage(logBufferBudget - oldLogBufferBudget); 857 858 /* 859 * Only reset the log buffer pool if the log buffer has already been 860 * initialized (we're updating an existing budget) and the log buffer 861 * budget has changed (resetting it is expensive and may cause I/O). 862 */ 863 if (!newEnv && oldLogBufferBudget != logBufferBudget) { 864 envImpl.getLogManager().resetPool(configManager); 865 } 866 } 867 868 /** 869 * Returns Runtime.maxMemory(), accounting for a MacOS bug. 870 * May return Long.MAX_VALUE if there is no inherent limit. 871 * Used by unit tests as well as by this class. 872 */ getRuntimeMaxMemory()873 public static long getRuntimeMaxMemory() { 874 875 /* Runtime.maxMemory is unreliable on MacOS Java 1.4.2. */ 876 if ("Mac OS X".equals(System.getProperty("os.name"))) { 877 String jvmVersion = System.getProperty("java.version"); 878 if (jvmVersion != null && jvmVersion.startsWith("1.4.2")) { 879 return Long.MAX_VALUE; /* Undetermined heap size. */ 880 } 881 } 882 883 return Runtime.getRuntime().maxMemory(); 884 } 885 886 /** 887 * Initialize the starting environment memory state. We really only need to 888 * recalibrate the tree and treeAdmin categories, since there are no locks 889 * and txns yet, and the items in the admin category are cleaner items and 890 * aren't affected by the recovery splicing process. 891 */ initCacheMemoryUsage(long dbTreeAdminMemory)892 void initCacheMemoryUsage(long dbTreeAdminMemory) { 893 long totalTree = 0; 894 long treeAdmin = 0; 895 for (IN in : envImpl.getInMemoryINs()) { 896 totalTree += in.getBudgetedMemorySize(); 897 treeAdmin += in.getTreeAdminMemorySize(); 898 } 899 refreshTreeMemoryUsage(totalTree); 900 refreshTreeAdminMemoryUsage(treeAdmin + dbTreeAdminMemory); 901 } 902 903 /** 904 * Called by INList when clearing tree memory usage. 905 */ refreshTreeAdminMemoryUsage(long newSize)906 void refreshTreeAdminMemoryUsage(long newSize) { 907 long oldSize = treeAdminMemoryUsage.getAndSet(newSize); 908 long diff = (newSize - oldSize); 909 910 if (DEBUG_TREEADMIN) { 911 System.err.println("RESET = " + newSize); 912 } 913 if (totals.updateCacheUsage(diff)) { 914 envImpl.alertEvictor(); 915 } 916 } 917 918 /** 919 * Called by INList when recalculating tree memory usage. 920 */ refreshTreeMemoryUsage(long newSize)921 void refreshTreeMemoryUsage(long newSize) { 922 long oldSize = treeMemoryUsage.getAndSet(newSize); 923 long diff = (newSize - oldSize); 924 925 if (totals.updateCacheUsage(diff)) { 926 envImpl.alertEvictor(); 927 } 928 } 929 930 /** 931 * Returns whether eviction of INList information is allowed. 932 * To prevent extreme cache churn, eviction of Btree information is 933 * prohibited unless the tree memory usage is above this minimum value. 934 */ isTreeUsageAboveMinimum()935 public boolean isTreeUsageAboveMinimum() { 936 return treeMemoryUsage.get() > minTreeMemoryUsage; 937 } 938 939 /** 940 * For unit tests. 941 */ getMinTreeMemoryUsage()942 public long getMinTreeMemoryUsage() { 943 return minTreeMemoryUsage; 944 } 945 946 /** 947 * Update the environment wide tree memory count, wake up the evictor if 948 * necessary. 949 * @param increment note that increment may be negative. 950 */ updateTreeMemoryUsage(long increment)951 public void updateTreeMemoryUsage(long increment) { 952 updateCounter(increment, treeMemoryUsage, "tree", DEBUG_TREE); 953 } 954 955 /** 956 * Update the environment wide txn memory count, wake up the evictor if 957 * necessary. 958 * @param increment note that increment may be negative. 959 */ updateTxnMemoryUsage(long increment)960 public void updateTxnMemoryUsage(long increment) { 961 updateCounter(increment, txnMemoryUsage, "txn", DEBUG_TXN); 962 } 963 964 /** 965 * Update the environment wide admin memory count, wake up the evictor if 966 * necessary. 967 * @param increment note that increment may be negative. 968 */ updateAdminMemoryUsage(long increment)969 public void updateAdminMemoryUsage(long increment) { 970 updateCounter(increment, adminMemoryUsage, "admin", DEBUG_ADMIN); 971 } 972 973 /** 974 * Update the treeAdmin memory count, wake up the evictor if necessary. 975 * @param increment note that increment may be negative. 976 */ updateTreeAdminMemoryUsage(long increment)977 public void updateTreeAdminMemoryUsage(long increment) { 978 updateCounter(increment, treeAdminMemoryUsage, "treeAdmin", 979 DEBUG_TREEADMIN); 980 } 981 updateCounter(long increment, AtomicLong counter, String debugName, boolean debug)982 private void updateCounter(long increment, 983 AtomicLong counter, 984 String debugName, 985 boolean debug) { 986 if (increment != 0) { 987 long newSize = counter.addAndGet(increment); 988 989 assert (sizeNotNegative(newSize)) : 990 makeErrorMessage(debugName, newSize, increment); 991 992 if (debug) { 993 if (increment > 0) { 994 System.err.println("INC-------- =" + increment + " " + 995 debugName + " " + newSize); 996 } else { 997 System.err.println("-------DEC=" + increment + " " + 998 debugName + " " + newSize); 999 } 1000 } 1001 1002 if (totals.updateCacheUsage(increment)) { 1003 envImpl.alertEvictor(); 1004 } 1005 } 1006 } 1007 sizeNotNegative(long newSize)1008 private boolean sizeNotNegative(long newSize) { 1009 1010 if (CLEANUP_DONE) { 1011 return (newSize >= 0); 1012 } 1013 return true; 1014 } 1015 updateLockMemoryUsage(long increment, int lockTableIndex)1016 public void updateLockMemoryUsage(long increment, int lockTableIndex) { 1017 if (increment != 0) { 1018 lockMemoryUsage.addAndGet(increment); 1019 1020 assert lockMemoryUsage.get() >= 0: 1021 makeErrorMessage("lockMem", 1022 lockMemoryUsage.get(), 1023 increment); 1024 if (DEBUG_LOCK) { 1025 if (increment > 0) { 1026 System.err.println("INC-------- =" + increment + 1027 " lock[" + 1028 lockTableIndex + "] " + 1029 lockMemoryUsage.get()); 1030 } else { 1031 System.err.println("-------DEC=" + increment + 1032 " lock[" + lockTableIndex + "] " + 1033 lockMemoryUsage.get()); 1034 } 1035 } 1036 1037 if (totals.updateCacheUsage(increment)) { 1038 envImpl.alertEvictor(); 1039 } 1040 } 1041 } 1042 makeErrorMessage(String memoryType, long total, long increment)1043 private String makeErrorMessage(String memoryType, 1044 long total, 1045 long increment) { 1046 return memoryType + "=" + total + 1047 " increment=" + increment + " " + 1048 LoggerUtils.getStackTrace(new Throwable()); 1049 } 1050 subtractCacheUsage()1051 void subtractCacheUsage() { 1052 totals.updateCacheUsage(0 - getLocalCacheUsage()); 1053 } 1054 getLocalCacheUsage()1055 private long getLocalCacheUsage() { 1056 return logBufferBudget + 1057 treeMemoryUsage.get() + 1058 adminMemoryUsage.get() + 1059 treeAdminMemoryUsage.get() + 1060 getLockMemoryUsage(); 1061 } 1062 getVariableCacheUsage()1063 long getVariableCacheUsage() { 1064 return treeMemoryUsage.get() + 1065 adminMemoryUsage.get() + 1066 treeAdminMemoryUsage.get() + 1067 getLockMemoryUsage(); 1068 } 1069 1070 /** 1071 * Public for unit testing. 1072 */ getLockMemoryUsage()1073 public long getLockMemoryUsage() { 1074 long accLockMemoryUsage = 1075 txnMemoryUsage.get() + lockMemoryUsage.get(); 1076 1077 return accLockMemoryUsage; 1078 } 1079 1080 /* 1081 * The following 2 methods are shorthand for getTotals.getXxx(). 1082 */ 1083 getCacheMemoryUsage()1084 public long getCacheMemoryUsage() { 1085 return totals.getCacheUsage(); 1086 } 1087 getMaxMemory()1088 public long getMaxMemory() { 1089 return totals.getMaxMemory(); 1090 } 1091 1092 /** 1093 * Used for unit testing. 1094 */ getTreeMemoryUsage()1095 public long getTreeMemoryUsage() { 1096 return treeMemoryUsage.get(); 1097 } 1098 1099 /** 1100 * Used for unit testing. 1101 */ getAdminMemoryUsage()1102 public long getAdminMemoryUsage() { 1103 return adminMemoryUsage.get(); 1104 } 1105 1106 /* 1107 * For unit testing 1108 */ getTreeAdminMemoryUsage()1109 public long getTreeAdminMemoryUsage() { 1110 return treeAdminMemoryUsage.get(); 1111 } 1112 getLogBufferBudget()1113 public long getLogBufferBudget() { 1114 return logBufferBudget; 1115 } 1116 getTrackerBudget()1117 public long getTrackerBudget() { 1118 return trackerBudget; 1119 } 1120 tupleOutputSize(TupleOutput o)1121 public static int tupleOutputSize(TupleOutput o) { 1122 return TUPLE_OUTPUT_OVERHEAD + 1123 byteArraySize(o.getBufferBytes().length); 1124 } 1125 1126 /** 1127 * Returns the memory size occupied by a byte array of a given length. All 1128 * arrays (regardless of element type) have the same overhead for a zero 1129 * length array. On 32b Java, there are 4 bytes included in that fixed 1130 * overhead that can be used for the first N elements -- however many fit 1131 * in 4 bytes. On 64b Java, there is no extra space included. In all 1132 * cases, space is allocated in 8 byte chunks. 1133 */ byteArraySize(int arrayLen)1134 public static int byteArraySize(int arrayLen) { 1135 1136 /* 1137 * ARRAY_OVERHEAD accounts for N bytes of data, which is 4 bytes on 32b 1138 * Java and 0 bytes on 64b Java. Data larger than N bytes is allocated 1139 * in 8 byte increments. 1140 */ 1141 int size = ARRAY_OVERHEAD; 1142 if (arrayLen > ARRAY_SIZE_INCLUDED) { 1143 size += ((arrayLen - ARRAY_SIZE_INCLUDED + 7) / 8) * 8; 1144 } 1145 1146 return size; 1147 } 1148 shortArraySize(int arrayLen)1149 public static int shortArraySize(int arrayLen) { 1150 return byteArraySize(arrayLen * 2); 1151 } 1152 intArraySize(int arrayLen)1153 public static int intArraySize(int arrayLen) { 1154 return byteArraySize(arrayLen * 4); 1155 } 1156 objectArraySize(int arrayLen)1157 public static int objectArraySize(int arrayLen) { 1158 return byteArraySize(arrayLen * OBJECT_ARRAY_ITEM_OVERHEAD); 1159 } 1160 loadStats()1161 StatGroup loadStats() { 1162 StatGroup stats = new StatGroup(MB_GROUP_NAME, MB_GROUP_DESC); 1163 new LongStat(stats, MB_SHARED_CACHE_TOTAL_BYTES, 1164 totals.isSharedCache() ? totals.getCacheUsage() : 0); 1165 new LongStat(stats, MB_TOTAL_BYTES, getLocalCacheUsage()); 1166 new LongStat(stats, MB_DATA_BYTES, 1167 treeMemoryUsage.get() + treeAdminMemoryUsage.get()); 1168 new LongStat(stats, MB_DATA_ADMIN_BYTES, treeAdminMemoryUsage.get()); 1169 new LongStat(stats, MB_ADMIN_BYTES, adminMemoryUsage.get()); 1170 new LongStat(stats, MB_LOCK_BYTES, getLockMemoryUsage()); 1171 1172 return stats; 1173 } 1174 1175 @Override toString()1176 public String toString() { 1177 StringBuilder sb = new StringBuilder(); 1178 sb.append("treeUsage = ").append(treeMemoryUsage.get()); 1179 sb.append("treeAdminUsage = ").append(treeAdminMemoryUsage.get()); 1180 sb.append("adminUsage = ").append(adminMemoryUsage.get()); 1181 sb.append("txnUsage = ").append(txnMemoryUsage.get()); 1182 sb.append("lockUsage = ").append(getLockMemoryUsage()); 1183 return sb.toString(); 1184 } 1185 getTotals()1186 public Totals getTotals() { 1187 return totals; 1188 } 1189 1190 /** 1191 * Common base class for shared and private totals. This abstraction 1192 * allows most other classes to be unaware of whether we're using a 1193 * SharedEvictor or PrivateEvictor. 1194 */ 1195 public abstract static class Totals { 1196 1197 long maxMemory; 1198 private long criticalThreshold; 1199 Totals()1200 private Totals() { 1201 maxMemory = 0; 1202 } 1203 setMaxMemory(long maxMemory)1204 private final void setMaxMemory(long maxMemory) { 1205 this.maxMemory = maxMemory; 1206 } 1207 getMaxMemory()1208 public final long getMaxMemory() { 1209 return maxMemory; 1210 } 1211 setCriticalThreshold(long criticalThreshold)1212 private final void setCriticalThreshold(long criticalThreshold) { 1213 this.criticalThreshold = criticalThreshold; 1214 } 1215 getCriticalThreshold()1216 public final long getCriticalThreshold() { 1217 return criticalThreshold; 1218 } 1219 getCacheUsage()1220 public abstract long getCacheUsage(); updateCacheUsage(long increment)1221 abstract boolean updateCacheUsage(long increment); isSharedCache()1222 abstract boolean isSharedCache(); 1223 } 1224 1225 /** 1226 * Totals for a single environment's non-shared cache. Used when 1227 * EnvironmentConfig.setSharedCache(false) and a PrivateEvictor are used. 1228 */ 1229 private static class PrivateTotals extends Totals { 1230 1231 private final MemoryBudget parent; 1232 PrivateTotals(MemoryBudget parent)1233 private PrivateTotals(MemoryBudget parent) { 1234 this.parent = parent; 1235 } 1236 1237 @Override getCacheUsage()1238 public final long getCacheUsage() { 1239 return parent.getLocalCacheUsage(); 1240 } 1241 1242 @Override updateCacheUsage(long increment)1243 final boolean updateCacheUsage(long increment) { 1244 return (parent.getLocalCacheUsage() > maxMemory); 1245 } 1246 1247 @Override isSharedCache()1248 final boolean isSharedCache() { 1249 return false; 1250 } 1251 } 1252 1253 /** 1254 * Totals for the multi-environment shared cache. Used when 1255 * EnvironmentConfig.setSharedCache(false) and the SharedEvictor are used. 1256 */ 1257 private static class SharedTotals extends Totals { 1258 1259 private final AtomicLong usage; 1260 SharedTotals()1261 private SharedTotals() { 1262 usage = new AtomicLong(); 1263 } 1264 1265 @Override getCacheUsage()1266 public final long getCacheUsage() { 1267 return usage.get(); 1268 } 1269 1270 @Override updateCacheUsage(long increment)1271 final boolean updateCacheUsage(long increment) { 1272 return (usage.addAndGet(increment) > maxMemory); 1273 } 1274 1275 @Override isSharedCache()1276 final boolean isSharedCache() { 1277 return true; 1278 } 1279 } 1280 } 1281