|
35 | 35 | import java.util.Map;
|
36 | 36 | import java.util.concurrent.atomic.AtomicLong;
|
37 | 37 | import java.util.concurrent.locks.ReentrantLock;
|
38 |
| -import java.util.function.BiConsumer; |
39 | 38 | import java.util.function.Function;
|
40 | 39 | import java.util.function.LongSupplier;
|
| 40 | +import java.util.stream.Collectors; |
41 | 41 |
|
42 | 42 | import static org.elasticsearch.core.Strings.format;
|
43 | 43 | import static org.elasticsearch.indices.breaker.BreakerSettings.CIRCUIT_BREAKER_LIMIT_SETTING;
|
@@ -397,78 +397,47 @@ public void checkParentLimit(long newBytesReserved, String label) throws Circuit
|
397 | 397 | long parentLimit = this.parentSettings.getLimit();
|
398 | 398 | if (memoryUsed.totalUsage > parentLimit && overLimitStrategy.overLimit(memoryUsed).totalUsage > parentLimit) {
|
399 | 399 | this.parentTripCount.incrementAndGet();
|
400 |
| - final String messageString = buildParentTripMessage( |
401 |
| - newBytesReserved, |
402 |
| - label, |
403 |
| - memoryUsed, |
404 |
| - parentLimit, |
405 |
| - this.trackRealMemoryUsage, |
406 |
| - this.breakers |
| 400 | + final StringBuilder message = new StringBuilder( |
| 401 | + "[parent] Data too large, data for [" |
| 402 | + + label |
| 403 | + + "]" |
| 404 | + + " would be [" |
| 405 | + + memoryUsed.totalUsage |
| 406 | + + "/" |
| 407 | + + new ByteSizeValue(memoryUsed.totalUsage) |
| 408 | + + "]" |
| 409 | + + ", which is larger than the limit of [" |
| 410 | + + parentLimit |
| 411 | + + "/" |
| 412 | + + new ByteSizeValue(parentLimit) |
| 413 | + + "]" |
407 | 414 | );
|
| 415 | + if (this.trackRealMemoryUsage) { |
| 416 | + final long realUsage = memoryUsed.baseUsage; |
| 417 | + message.append(", real usage: ["); |
| 418 | + message.append(realUsage); |
| 419 | + message.append("/"); |
| 420 | + message.append(new ByteSizeValue(realUsage)); |
| 421 | + message.append("], new bytes reserved: ["); |
| 422 | + message.append(newBytesReserved); |
| 423 | + message.append("/"); |
| 424 | + message.append(new ByteSizeValue(newBytesReserved)); |
| 425 | + message.append("]"); |
| 426 | + } |
| 427 | + message.append(", usages ["); |
| 428 | + message.append(this.breakers.entrySet().stream().map(e -> { |
| 429 | + final CircuitBreaker breaker = e.getValue(); |
| 430 | + final long breakerUsed = (long) (breaker.getUsed() * breaker.getOverhead()); |
| 431 | + return e.getKey() + "=" + breakerUsed + "/" + new ByteSizeValue(breakerUsed); |
| 432 | + }).collect(Collectors.joining(", "))); |
| 433 | + message.append("]"); |
408 | 434 | // derive durability of a tripped parent breaker depending on whether the majority of memory tracked by
|
409 | 435 | // child circuit breakers is categorized as transient or permanent.
|
410 | 436 | CircuitBreaker.Durability durability = memoryUsed.transientChildUsage >= memoryUsed.permanentChildUsage
|
411 | 437 | ? CircuitBreaker.Durability.TRANSIENT
|
412 | 438 | : CircuitBreaker.Durability.PERMANENT;
|
413 |
| - logger.debug(() -> format("%s", messageString)); |
414 |
| - throw new CircuitBreakingException(messageString, memoryUsed.totalUsage, parentLimit, durability); |
415 |
| - } |
416 |
| - } |
417 |
| - |
418 |
| - // exposed for tests |
419 |
| - static String buildParentTripMessage( |
420 |
| - long newBytesReserved, |
421 |
| - String label, |
422 |
| - MemoryUsage memoryUsed, |
423 |
| - long parentLimit, |
424 |
| - boolean trackRealMemoryUsage, |
425 |
| - Map<String, CircuitBreaker> breakers |
426 |
| - ) { |
427 |
| - final var message = new StringBuilder(); |
428 |
| - message.append("[parent] Data too large, data for ["); |
429 |
| - message.append(label); |
430 |
| - message.append("] would be ["); |
431 |
| - appendBytesSafe(message, memoryUsed.totalUsage); |
432 |
| - message.append("], which is larger than the limit of ["); |
433 |
| - appendBytesSafe(message, parentLimit); |
434 |
| - message.append("]"); |
435 |
| - if (trackRealMemoryUsage) { |
436 |
| - final long realUsage = memoryUsed.baseUsage; |
437 |
| - message.append(", real usage: ["); |
438 |
| - appendBytesSafe(message, realUsage); |
439 |
| - message.append("], new bytes reserved: ["); |
440 |
| - appendBytesSafe(message, newBytesReserved); |
441 |
| - message.append("]"); |
442 |
| - } |
443 |
| - message.append(", usages ["); |
444 |
| - breakers.forEach(new BiConsumer<>() { |
445 |
| - private boolean first = true; |
446 |
| - |
447 |
| - @Override |
448 |
| - public void accept(String key, CircuitBreaker breaker) { |
449 |
| - if (first) { |
450 |
| - first = false; |
451 |
| - } else { |
452 |
| - message.append(", "); |
453 |
| - } |
454 |
| - message.append(key).append("="); |
455 |
| - appendBytesSafe(message, (long) (breaker.getUsed() * breaker.getOverhead())); |
456 |
| - } |
457 |
| - }); |
458 |
| - message.append("]"); |
459 |
| - return message.toString(); |
460 |
| - } |
461 |
| - |
462 |
| - static void appendBytesSafe(StringBuilder stringBuilder, long bytes) { |
463 |
| - stringBuilder.append(bytes); |
464 |
| - if (bytes >= 0) { |
465 |
| - stringBuilder.append("/"); |
466 |
| - stringBuilder.append(new ByteSizeValue(bytes)); |
467 |
| - } else { |
468 |
| - // Something's definitely wrong, maybe a breaker was freed twice? Still, we're just creating an exception message here, so we |
469 |
| - // should keep going if we're running in production. |
470 |
| - logger.error("negative value in circuit breaker: {}", stringBuilder); |
471 |
| - assert permitNegativeValues : stringBuilder.toString(); |
| 439 | + logger.debug(() -> format("%s", message.toString())); |
| 440 | + throw new CircuitBreakingException(message.toString(), memoryUsed.totalUsage, parentLimit, durability); |
472 | 441 | }
|
473 | 442 | }
|
474 | 443 |
|
@@ -667,7 +636,4 @@ TimeValue getLockTimeout() {
|
667 | 636 | return lockTimeout;
|
668 | 637 | }
|
669 | 638 | }
|
670 |
| - |
671 |
| - // exposed for testing |
672 |
| - static boolean permitNegativeValues = false; |
673 | 639 | }
|
0 commit comments