|
37 | 37 | import java.util.Map; |
38 | 38 | import java.util.concurrent.atomic.AtomicLong; |
39 | 39 | import java.util.concurrent.locks.ReentrantLock; |
40 | | -import java.util.function.BiConsumer; |
41 | 40 | import java.util.function.Function; |
42 | 41 | import java.util.function.LongSupplier; |
43 | 42 | import java.util.stream.Collectors; |
@@ -418,78 +417,47 @@ public void checkParentLimit(long newBytesReserved, String label) throws Circuit |
418 | 417 | long parentLimit = this.parentSettings.getLimit(); |
419 | 418 | if (memoryUsed.totalUsage > parentLimit && overLimitStrategy.overLimit(memoryUsed).totalUsage > parentLimit) { |
420 | 419 | this.parentTripCount.incrementAndGet(); |
421 | | - final String messageString = buildParentTripMessage( |
422 | | - newBytesReserved, |
423 | | - label, |
424 | | - memoryUsed, |
425 | | - parentLimit, |
426 | | - this.trackRealMemoryUsage, |
427 | | - this.breakers |
| 420 | + final StringBuilder message = new StringBuilder( |
| 421 | + "[parent] Data too large, data for [" |
| 422 | + + label |
| 423 | + + "]" |
| 424 | + + " would be [" |
| 425 | + + memoryUsed.totalUsage |
| 426 | + + "/" |
| 427 | + + new ByteSizeValue(memoryUsed.totalUsage) |
| 428 | + + "]" |
| 429 | + + ", which is larger than the limit of [" |
| 430 | + + parentLimit |
| 431 | + + "/" |
| 432 | + + new ByteSizeValue(parentLimit) |
| 433 | + + "]" |
428 | 434 | ); |
| 435 | + if (this.trackRealMemoryUsage) { |
| 436 | + final long realUsage = memoryUsed.baseUsage; |
| 437 | + message.append(", real usage: ["); |
| 438 | + message.append(realUsage); |
| 439 | + message.append("/"); |
| 440 | + message.append(new ByteSizeValue(realUsage)); |
| 441 | + message.append("], new bytes reserved: ["); |
| 442 | + message.append(newBytesReserved); |
| 443 | + message.append("/"); |
| 444 | + message.append(new ByteSizeValue(newBytesReserved)); |
| 445 | + message.append("]"); |
| 446 | + } |
| 447 | + message.append(", usages ["); |
| 448 | + message.append(this.breakers.entrySet().stream().map(e -> { |
| 449 | + final CircuitBreaker breaker = e.getValue(); |
| 450 | + final long breakerUsed = (long) (breaker.getUsed() * breaker.getOverhead()); |
| 451 | + return e.getKey() + "=" + breakerUsed + "/" + new ByteSizeValue(breakerUsed); |
| 452 | + }).collect(Collectors.joining(", "))); |
| 453 | + message.append("]"); |
429 | 454 | // derive durability of a tripped parent breaker depending on whether the majority of memory tracked by |
430 | 455 | // child circuit breakers is categorized as transient or permanent. |
431 | 456 | CircuitBreaker.Durability durability = memoryUsed.transientChildUsage >= memoryUsed.permanentChildUsage |
432 | 457 | ? CircuitBreaker.Durability.TRANSIENT |
433 | 458 | : CircuitBreaker.Durability.PERMANENT; |
434 | | - logger.debug(() -> new ParameterizedMessage("{}", messageString)); |
435 | | - throw new CircuitBreakingException(messageString, memoryUsed.totalUsage, parentLimit, durability); |
436 | | - } |
437 | | - } |
438 | | - |
439 | | - // exposed for tests |
440 | | - static String buildParentTripMessage( |
441 | | - long newBytesReserved, |
442 | | - String label, |
443 | | - MemoryUsage memoryUsed, |
444 | | - long parentLimit, |
445 | | - boolean trackRealMemoryUsage, |
446 | | - Map<String, CircuitBreaker> breakers |
447 | | - ) { |
448 | | - final StringBuilder message = new StringBuilder(); |
449 | | - message.append("[parent] Data too large, data for ["); |
450 | | - message.append(label); |
451 | | - message.append("] would be ["); |
452 | | - appendBytesSafe(message, memoryUsed.totalUsage); |
453 | | - message.append("], which is larger than the limit of ["); |
454 | | - appendBytesSafe(message, parentLimit); |
455 | | - message.append("]"); |
456 | | - if (trackRealMemoryUsage) { |
457 | | - final long realUsage = memoryUsed.baseUsage; |
458 | | - message.append(", real usage: ["); |
459 | | - appendBytesSafe(message, realUsage); |
460 | | - message.append("], new bytes reserved: ["); |
461 | | - appendBytesSafe(message, newBytesReserved); |
462 | | - message.append("]"); |
463 | | - } |
464 | | - message.append(", usages ["); |
465 | | - breakers.forEach(new BiConsumer<String, CircuitBreaker>() { |
466 | | - private boolean first = true; |
467 | | - |
468 | | - @Override |
469 | | - public void accept(String key, CircuitBreaker breaker) { |
470 | | - if (first) { |
471 | | - first = false; |
472 | | - } else { |
473 | | - message.append(", "); |
474 | | - } |
475 | | - message.append(key).append("="); |
476 | | - appendBytesSafe(message, (long) (breaker.getUsed() * breaker.getOverhead())); |
477 | | - } |
478 | | - }); |
479 | | - message.append("]"); |
480 | | - return message.toString(); |
481 | | - } |
482 | | - |
483 | | - static void appendBytesSafe(StringBuilder stringBuilder, long bytes) { |
484 | | - stringBuilder.append(bytes); |
485 | | - if (bytes >= 0) { |
486 | | - stringBuilder.append("/"); |
487 | | - stringBuilder.append(new ByteSizeValue(bytes)); |
488 | | - } else { |
489 | | - // Something's definitely wrong, maybe a breaker was freed twice? Still, we're just creating an exception message here, so we |
490 | | - // should keep going if we're running in production. |
491 | | - logger.error("negative value in circuit breaker: {}", stringBuilder); |
492 | | - assert permitNegativeValues : stringBuilder.toString(); |
| 459 | + logger.debug(() -> new ParameterizedMessage("{}", message.toString())); |
| 460 | + throw new CircuitBreakingException(message.toString(), memoryUsed.totalUsage, parentLimit, durability); |
493 | 461 | } |
494 | 462 | } |
495 | 463 |
|
@@ -688,7 +656,4 @@ TimeValue getLockTimeout() { |
688 | 656 | return lockTimeout; |
689 | 657 | } |
690 | 658 | } |
691 | | - |
692 | | - // exposed for testing |
693 | | - static boolean permitNegativeValues = false; |
694 | 659 | } |
0 commit comments