mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-18 19:05:06 +00:00
Allow setting individual breakers to "noop" breakers
This adds a NoopCircuitBreaker, and then adds the settings `indices.breaker.fielddata.type` and `indices.breaker.request.type`, which can be set to "noop" in order to use a breaker that will never break, and incurs no overhead during computation. This also refactors the tests for the CircuitBreakerService to use @Before and @After functions as well as adding settings in ElasticsearchIntegrationTest to occasionally use NOOP breakers for all tests.
This commit is contained in:
parent
74586e2867
commit
1c4d07c96f
@ -94,6 +94,7 @@ public class ClusterDynamicSettingsModule extends AbstractModule {
|
|||||||
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, Validator.NON_NEGATIVE_DOUBLE);
|
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, Validator.NON_NEGATIVE_DOUBLE);
|
||||||
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, Validator.MEMORY_SIZE);
|
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, Validator.MEMORY_SIZE);
|
||||||
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, Validator.NON_NEGATIVE_DOUBLE);
|
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, Validator.NON_NEGATIVE_DOUBLE);
|
||||||
|
clusterDynamicSettings.addDynamicSetting(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_TYPE_SETTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDynamicSettings(String... settings) {
|
public void addDynamicSettings(String... settings) {
|
||||||
|
@ -24,6 +24,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
|||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for an object that can be incremented, breaking after some
|
* Interface for an object that can be incremented, breaking after some
|
||||||
@ -68,6 +69,28 @@ public interface CircuitBreaker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
// A regular or child MemoryCircuitBreaker
|
||||||
|
MEMORY,
|
||||||
|
// A special parent-type for the hierarchy breaker service
|
||||||
|
PARENT,
|
||||||
|
// A breaker where every action is a noop, it never breaks
|
||||||
|
NOOP;
|
||||||
|
|
||||||
|
public static Type parseValue(String value) {
|
||||||
|
switch(value.toLowerCase(Locale.ROOT)) {
|
||||||
|
case "noop":
|
||||||
|
return Type.NOOP;
|
||||||
|
case "parent":
|
||||||
|
return Type.PARENT;
|
||||||
|
case "memory":
|
||||||
|
return Type.MEMORY;
|
||||||
|
default:
|
||||||
|
throw new ElasticsearchIllegalArgumentException("No CircuitBreaker with type: " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trip the circuit breaker
|
* Trip the circuit breaker
|
||||||
* @param fieldName name of the field responsible for tripping the breaker
|
* @param fieldName name of the field responsible for tripping the breaker
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.elasticsearch.common.breaker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A CircuitBreaker that doesn't increment or adjust, and all operations are
|
||||||
|
* basically noops
|
||||||
|
*/
|
||||||
|
public class NoopCircuitBreaker implements CircuitBreaker {
|
||||||
|
|
||||||
|
private final Name name;
|
||||||
|
|
||||||
|
public NoopCircuitBreaker(Name name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void circuitBreak(String fieldName, long bytesNeeded) {
|
||||||
|
// noop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double addEstimateBytesAndMaybeBreak(long bytes, String label) throws CircuitBreakingException {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long addWithoutBreaking(long bytes) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getUsed() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getLimit() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getOverhead() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getTrippedCount() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Name getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
@ -30,11 +30,17 @@ public class BreakerSettings {
|
|||||||
private final CircuitBreaker.Name name;
|
private final CircuitBreaker.Name name;
|
||||||
private final long limitBytes;
|
private final long limitBytes;
|
||||||
private final double overhead;
|
private final double overhead;
|
||||||
|
private final CircuitBreaker.Type type;
|
||||||
|
|
||||||
public BreakerSettings(CircuitBreaker.Name name, long limitBytes, double overhead) {
|
public BreakerSettings(CircuitBreaker.Name name, long limitBytes, double overhead) {
|
||||||
|
this(name, limitBytes, overhead, CircuitBreaker.Type.MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BreakerSettings(CircuitBreaker.Name name, long limitBytes, double overhead, CircuitBreaker.Type type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.limitBytes = limitBytes;
|
this.limitBytes = limitBytes;
|
||||||
this.overhead = overhead;
|
this.overhead = overhead;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CircuitBreaker.Name getName() {
|
public CircuitBreaker.Name getName() {
|
||||||
@ -49,9 +55,14 @@ public class BreakerSettings {
|
|||||||
return this.overhead;
|
return this.overhead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CircuitBreaker.Type getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[" + this.name.toString() +
|
return "[" + this.name.toString() +
|
||||||
|
",type=" + this.type.toString() +
|
||||||
",limit=" + this.limitBytes + "/" + new ByteSizeValue(this.limitBytes) +
|
",limit=" + this.limitBytes + "/" + new ByteSizeValue(this.limitBytes) +
|
||||||
",overhead=" + this.overhead + "]";
|
",overhead=" + this.overhead + "]";
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||||||
|
|
||||||
public class CircuitBreakerModule extends AbstractModule {
|
public class CircuitBreakerModule extends AbstractModule {
|
||||||
|
|
||||||
public static final String IMPL = "indices.breaker.breaker_impl";
|
public static final String IMPL = "indices.breaker.type";
|
||||||
|
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import org.elasticsearch.ElasticsearchIllegalStateException;
|
|||||||
import org.elasticsearch.common.breaker.ChildMemoryCircuitBreaker;
|
import org.elasticsearch.common.breaker.ChildMemoryCircuitBreaker;
|
||||||
import org.elasticsearch.common.breaker.CircuitBreaker;
|
import org.elasticsearch.common.breaker.CircuitBreaker;
|
||||||
import org.elasticsearch.common.breaker.CircuitBreakingException;
|
import org.elasticsearch.common.breaker.CircuitBreakingException;
|
||||||
|
import org.elasticsearch.common.breaker.NoopCircuitBreaker;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
@ -53,18 +54,21 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|||||||
|
|
||||||
public static final String FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING = "indices.breaker.fielddata.limit";
|
public static final String FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING = "indices.breaker.fielddata.limit";
|
||||||
public static final String FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING = "indices.breaker.fielddata.overhead";
|
public static final String FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING = "indices.breaker.fielddata.overhead";
|
||||||
|
public static final String FIELDDATA_CIRCUIT_BREAKER_TYPE_SETTING = "indices.breaker.fielddata.type";
|
||||||
public static final String DEFAULT_FIELDDATA_BREAKER_LIMIT = "60%";
|
public static final String DEFAULT_FIELDDATA_BREAKER_LIMIT = "60%";
|
||||||
public static final double DEFAULT_FIELDDATA_OVERHEAD_CONSTANT = 1.03;
|
public static final double DEFAULT_FIELDDATA_OVERHEAD_CONSTANT = 1.03;
|
||||||
|
|
||||||
public static final String REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING = "indices.breaker.request.limit";
|
public static final String REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING = "indices.breaker.request.limit";
|
||||||
public static final String REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING = "indices.breaker.request.overhead";
|
public static final String REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING = "indices.breaker.request.overhead";
|
||||||
|
public static final String REQUEST_CIRCUIT_BREAKER_TYPE_SETTING = "indices.breaker.request.type";
|
||||||
public static final String DEFAULT_REQUEST_BREAKER_LIMIT = "40%";
|
public static final String DEFAULT_REQUEST_BREAKER_LIMIT = "40%";
|
||||||
|
|
||||||
|
public static final String DEFAULT_BREAKER_TYPE = "memory";
|
||||||
|
|
||||||
private volatile BreakerSettings parentSettings;
|
private volatile BreakerSettings parentSettings;
|
||||||
private volatile BreakerSettings fielddataSettings;
|
private volatile BreakerSettings fielddataSettings;
|
||||||
private volatile BreakerSettings requestSettings;
|
private volatile BreakerSettings requestSettings;
|
||||||
|
|
||||||
|
|
||||||
// Tripped count for when redistribution was attempted but wasn't successful
|
// Tripped count for when redistribution was attempted but wasn't successful
|
||||||
private final AtomicLong parentTripCount = new AtomicLong(0);
|
private final AtomicLong parentTripCount = new AtomicLong(0);
|
||||||
|
|
||||||
@ -92,24 +96,43 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|||||||
|
|
||||||
this.fielddataSettings = new BreakerSettings(CircuitBreaker.Name.FIELDDATA,
|
this.fielddataSettings = new BreakerSettings(CircuitBreaker.Name.FIELDDATA,
|
||||||
settings.getAsMemory(FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, compatibilityFielddataLimitDefault).bytes(),
|
settings.getAsMemory(FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, compatibilityFielddataLimitDefault).bytes(),
|
||||||
settings.getAsDouble(FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, compatibilityFielddataOverheadDefault));
|
settings.getAsDouble(FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, compatibilityFielddataOverheadDefault),
|
||||||
|
CircuitBreaker.Type.parseValue(settings.get(FIELDDATA_CIRCUIT_BREAKER_TYPE_SETTING, DEFAULT_BREAKER_TYPE))
|
||||||
|
);
|
||||||
|
|
||||||
this.requestSettings = new BreakerSettings(CircuitBreaker.Name.REQUEST,
|
this.requestSettings = new BreakerSettings(CircuitBreaker.Name.REQUEST,
|
||||||
settings.getAsMemory(REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, DEFAULT_REQUEST_BREAKER_LIMIT).bytes(),
|
settings.getAsMemory(REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, DEFAULT_REQUEST_BREAKER_LIMIT).bytes(),
|
||||||
settings.getAsDouble(REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0));
|
settings.getAsDouble(REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0),
|
||||||
|
CircuitBreaker.Type.parseValue(settings.get(REQUEST_CIRCUIT_BREAKER_TYPE_SETTING, DEFAULT_BREAKER_TYPE))
|
||||||
|
);
|
||||||
|
|
||||||
// Validate the configured settings
|
// Validate the configured settings
|
||||||
validateSettings(new BreakerSettings[] {this.requestSettings, this.fielddataSettings});
|
validateSettings(new BreakerSettings[] {this.requestSettings, this.fielddataSettings});
|
||||||
|
|
||||||
this.parentSettings = new BreakerSettings(CircuitBreaker.Name.PARENT,
|
this.parentSettings = new BreakerSettings(CircuitBreaker.Name.PARENT,
|
||||||
settings.getAsMemory(TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, DEFAULT_TOTAL_CIRCUIT_BREAKER_LIMIT).bytes(), 1.0);
|
settings.getAsMemory(TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, DEFAULT_TOTAL_CIRCUIT_BREAKER_LIMIT).bytes(), 1.0, CircuitBreaker.Type.PARENT);
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("parent circuit breaker with settings {}", this.parentSettings);
|
logger.trace("parent circuit breaker with settings {}", this.parentSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<CircuitBreaker.Name, CircuitBreaker> tempBreakers = new HashMap<>();
|
Map<CircuitBreaker.Name, CircuitBreaker> tempBreakers = new HashMap<>();
|
||||||
tempBreakers.put(CircuitBreaker.Name.FIELDDATA, new ChildMemoryCircuitBreaker(fielddataSettings, logger, this, CircuitBreaker.Name.FIELDDATA));
|
|
||||||
tempBreakers.put(CircuitBreaker.Name.REQUEST, new ChildMemoryCircuitBreaker(requestSettings, logger, this, CircuitBreaker.Name.REQUEST));
|
CircuitBreaker fielddataBreaker;
|
||||||
|
if (fielddataSettings.getType() == CircuitBreaker.Type.NOOP) {
|
||||||
|
fielddataBreaker = new NoopCircuitBreaker(CircuitBreaker.Name.FIELDDATA);
|
||||||
|
} else {
|
||||||
|
fielddataBreaker = new ChildMemoryCircuitBreaker(fielddataSettings, logger, this, CircuitBreaker.Name.FIELDDATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitBreaker requestBreaker;
|
||||||
|
if (requestSettings.getType() == CircuitBreaker.Type.NOOP) {
|
||||||
|
requestBreaker = new NoopCircuitBreaker(CircuitBreaker.Name.REQUEST);
|
||||||
|
} else {
|
||||||
|
requestBreaker = new ChildMemoryCircuitBreaker(requestSettings, logger, this, CircuitBreaker.Name.REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempBreakers.put(CircuitBreaker.Name.FIELDDATA, fielddataBreaker);
|
||||||
|
tempBreakers.put(CircuitBreaker.Name.REQUEST, requestBreaker);
|
||||||
this.breakers = ImmutableMap.copyOf(tempBreakers);
|
this.breakers = ImmutableMap.copyOf(tempBreakers);
|
||||||
|
|
||||||
nodeSettingsService.addListener(new ApplySettings());
|
nodeSettingsService.addListener(new ApplySettings());
|
||||||
@ -121,6 +144,8 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|||||||
public void onRefreshSettings(Settings settings) {
|
public void onRefreshSettings(Settings settings) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
|
||||||
|
String newRequestType = settings.get(REQUEST_CIRCUIT_BREAKER_TYPE_SETTING, null);
|
||||||
|
|
||||||
// Fielddata settings
|
// Fielddata settings
|
||||||
BreakerSettings newFielddataSettings = HierarchyCircuitBreakerService.this.fielddataSettings;
|
BreakerSettings newFielddataSettings = HierarchyCircuitBreakerService.this.fielddataSettings;
|
||||||
ByteSizeValue newFielddataMax = settings.getAsMemory(FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
ByteSizeValue newFielddataMax = settings.getAsMemory(FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
||||||
@ -130,19 +155,21 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|||||||
long newFielddataLimitBytes = newFielddataMax == null ? HierarchyCircuitBreakerService.this.fielddataSettings.getLimit() : newFielddataMax.bytes();
|
long newFielddataLimitBytes = newFielddataMax == null ? HierarchyCircuitBreakerService.this.fielddataSettings.getLimit() : newFielddataMax.bytes();
|
||||||
newFielddataOverhead = newFielddataOverhead == null ? HierarchyCircuitBreakerService.this.fielddataSettings.getOverhead() : newFielddataOverhead;
|
newFielddataOverhead = newFielddataOverhead == null ? HierarchyCircuitBreakerService.this.fielddataSettings.getOverhead() : newFielddataOverhead;
|
||||||
|
|
||||||
newFielddataSettings = new BreakerSettings(CircuitBreaker.Name.FIELDDATA, newFielddataLimitBytes, newFielddataOverhead);
|
newFielddataSettings = new BreakerSettings(CircuitBreaker.Name.FIELDDATA, newFielddataLimitBytes, newFielddataOverhead,
|
||||||
|
HierarchyCircuitBreakerService.this.fielddataSettings.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request settings
|
// Request settings
|
||||||
BreakerSettings newRequestSettings = HierarchyCircuitBreakerService.this.requestSettings;
|
BreakerSettings newRequestSettings = HierarchyCircuitBreakerService.this.requestSettings;
|
||||||
ByteSizeValue newRequestMax = settings.getAsMemory(REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
ByteSizeValue newRequestMax = settings.getAsMemory(REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
||||||
Double newRequestOverhead = settings.getAsDouble(REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, null);
|
Double newRequestOverhead = settings.getAsDouble(REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, null);
|
||||||
if (newRequestMax != null || newRequestOverhead != null) {
|
if (newRequestMax != null || newRequestOverhead != null || newRequestType != null) {
|
||||||
changed = true;
|
changed = true;
|
||||||
long newRequestLimitBytes = newRequestMax == null ? HierarchyCircuitBreakerService.this.requestSettings.getLimit() : newRequestMax.bytes();
|
long newRequestLimitBytes = newRequestMax == null ? HierarchyCircuitBreakerService.this.requestSettings.getLimit() : newRequestMax.bytes();
|
||||||
newRequestOverhead = newRequestOverhead == null ? HierarchyCircuitBreakerService.this.requestSettings.getOverhead() : newRequestOverhead;
|
newRequestOverhead = newRequestOverhead == null ? HierarchyCircuitBreakerService.this.requestSettings.getOverhead() : newRequestOverhead;
|
||||||
|
CircuitBreaker.Type newType = newRequestType == null ? HierarchyCircuitBreakerService.this.requestSettings.getType() : CircuitBreaker.Type.parseValue(newRequestType);
|
||||||
|
|
||||||
newRequestSettings = new BreakerSettings(CircuitBreaker.Name.REQUEST, newRequestLimitBytes, newRequestOverhead);
|
newRequestSettings = new BreakerSettings(CircuitBreaker.Name.REQUEST, newRequestLimitBytes, newRequestOverhead, newType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent settings
|
// Parent settings
|
||||||
@ -151,23 +178,51 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|||||||
ByteSizeValue newParentMax = settings.getAsMemory(TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
ByteSizeValue newParentMax = settings.getAsMemory(TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, null);
|
||||||
if (newParentMax != null && (newParentMax.bytes() != oldParentMax)) {
|
if (newParentMax != null && (newParentMax.bytes() != oldParentMax)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
newParentSettings = new BreakerSettings(CircuitBreaker.Name.PARENT, newParentMax.bytes(), 1.0);
|
newParentSettings = new BreakerSettings(CircuitBreaker.Name.PARENT, newParentMax.bytes(), 1.0, CircuitBreaker.Type.PARENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
// change all the things
|
// change all the things
|
||||||
validateSettings(new BreakerSettings[] {newFielddataSettings, newRequestSettings});
|
validateSettings(new BreakerSettings[]{newFielddataSettings, newRequestSettings});
|
||||||
logger.info("Updating settings parent: {}, fielddata: {}, request: {}", newParentSettings, newFielddataSettings, newRequestSettings);
|
logger.info("Updating settings parent: {}, fielddata: {}, request: {}", newParentSettings, newFielddataSettings, newRequestSettings);
|
||||||
|
CircuitBreaker.Type previousFielddataType = HierarchyCircuitBreakerService.this.fielddataSettings.getType();
|
||||||
|
CircuitBreaker.Type previousRequestType = HierarchyCircuitBreakerService.this.requestSettings.getType();
|
||||||
HierarchyCircuitBreakerService.this.parentSettings = newParentSettings;
|
HierarchyCircuitBreakerService.this.parentSettings = newParentSettings;
|
||||||
HierarchyCircuitBreakerService.this.fielddataSettings = newFielddataSettings;
|
HierarchyCircuitBreakerService.this.fielddataSettings = newFielddataSettings;
|
||||||
HierarchyCircuitBreakerService.this.requestSettings = newRequestSettings;
|
HierarchyCircuitBreakerService.this.requestSettings = newRequestSettings;
|
||||||
|
|
||||||
Map<CircuitBreaker.Name, CircuitBreaker> tempBreakers = new HashMap<>();
|
Map<CircuitBreaker.Name, CircuitBreaker> tempBreakers = new HashMap<>();
|
||||||
tempBreakers.put(CircuitBreaker.Name.FIELDDATA, new ChildMemoryCircuitBreaker(newFielddataSettings,
|
CircuitBreaker fielddataBreaker;
|
||||||
(ChildMemoryCircuitBreaker)HierarchyCircuitBreakerService.this.breakers.get(CircuitBreaker.Name.FIELDDATA),
|
if (newFielddataSettings.getType() == CircuitBreaker.Type.NOOP) {
|
||||||
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.FIELDDATA));
|
fielddataBreaker = new NoopCircuitBreaker(CircuitBreaker.Name.FIELDDATA);
|
||||||
tempBreakers.put(CircuitBreaker.Name.REQUEST, new ChildMemoryCircuitBreaker(newRequestSettings,
|
} else {
|
||||||
(ChildMemoryCircuitBreaker)HierarchyCircuitBreakerService.this.breakers.get(CircuitBreaker.Name.REQUEST),
|
if (previousFielddataType == CircuitBreaker.Type.MEMORY) {
|
||||||
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.REQUEST));
|
fielddataBreaker = new ChildMemoryCircuitBreaker(newFielddataSettings,
|
||||||
|
(ChildMemoryCircuitBreaker) HierarchyCircuitBreakerService.this.breakers.get(CircuitBreaker.Name.FIELDDATA),
|
||||||
|
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.FIELDDATA);
|
||||||
|
} else {
|
||||||
|
fielddataBreaker = new ChildMemoryCircuitBreaker(newFielddataSettings,
|
||||||
|
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.FIELDDATA);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CircuitBreaker requestBreaker;
|
||||||
|
if (newRequestSettings.getType() == CircuitBreaker.Type.NOOP) {
|
||||||
|
requestBreaker = new NoopCircuitBreaker(CircuitBreaker.Name.REQUEST);
|
||||||
|
} else {
|
||||||
|
if (previousRequestType == CircuitBreaker.Type.MEMORY) {
|
||||||
|
requestBreaker = new ChildMemoryCircuitBreaker(newRequestSettings,
|
||||||
|
(ChildMemoryCircuitBreaker)HierarchyCircuitBreakerService.this.breakers.get(CircuitBreaker.Name.REQUEST),
|
||||||
|
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.REQUEST);
|
||||||
|
} else {
|
||||||
|
requestBreaker = new ChildMemoryCircuitBreaker(newRequestSettings,
|
||||||
|
logger, HierarchyCircuitBreakerService.this, CircuitBreaker.Name.REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tempBreakers.put(CircuitBreaker.Name.FIELDDATA, fielddataBreaker);
|
||||||
|
tempBreakers.put(CircuitBreaker.Name.REQUEST, requestBreaker);
|
||||||
HierarchyCircuitBreakerService.this.breakers = ImmutableMap.copyOf(tempBreakers);
|
HierarchyCircuitBreakerService.this.breakers = ImmutableMap.copyOf(tempBreakers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,28 +20,22 @@
|
|||||||
package org.elasticsearch.indices.breaker;
|
package org.elasticsearch.indices.breaker;
|
||||||
|
|
||||||
import org.elasticsearch.common.breaker.CircuitBreaker;
|
import org.elasticsearch.common.breaker.CircuitBreaker;
|
||||||
import org.elasticsearch.common.breaker.MemoryCircuitBreaker;
|
import org.elasticsearch.common.breaker.NoopCircuitBreaker;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
|
||||||
import org.elasticsearch.common.logging.Loggers;
|
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that returns a breaker that never breaks
|
* Class that returns a breaker that never breaks
|
||||||
*/
|
*/
|
||||||
public class NoneCircuitBreakerService extends CircuitBreakerService {
|
public class NoneCircuitBreakerService extends CircuitBreakerService {
|
||||||
|
|
||||||
private final ESLogger logger = Loggers.getLogger(NoneCircuitBreakerService.class);
|
private final CircuitBreaker breaker = new NoopCircuitBreaker(CircuitBreaker.Name.FIELDDATA);
|
||||||
|
|
||||||
private final MemoryCircuitBreaker breaker = new MemoryCircuitBreaker(new ByteSizeValue(Long.MAX_VALUE), 0.0, logger);
|
|
||||||
|
|
||||||
public NoneCircuitBreakerService() {
|
public NoneCircuitBreakerService() {
|
||||||
super(ImmutableSettings.EMPTY);
|
super(ImmutableSettings.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MemoryCircuitBreaker getBreaker(CircuitBreaker.Name name) {
|
public CircuitBreaker getBreaker(CircuitBreaker.Name name) {
|
||||||
return breaker;
|
return breaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,21 +22,26 @@ package org.elasticsearch.indices.memory.breaker;
|
|||||||
import org.elasticsearch.ExceptionsHelper;
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
||||||
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
|
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.common.breaker.CircuitBreaker;
|
import org.elasticsearch.common.breaker.CircuitBreaker;
|
||||||
import org.elasticsearch.common.collect.MapBuilder;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.indices.breaker.CircuitBreakerStats;
|
import org.elasticsearch.indices.breaker.CircuitBreakerStats;
|
||||||
import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
|
import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
|
||||||
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||||
@ -45,7 +50,8 @@ import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
|||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
|
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration tests for InternalCircuitBreakerService
|
* Integration tests for InternalCircuitBreakerService
|
||||||
@ -53,127 +59,123 @@ import static org.hamcrest.Matchers.*;
|
|||||||
@ClusterScope(scope = TEST, randomDynamicTemplates = false)
|
@ClusterScope(scope = TEST, randomDynamicTemplates = false)
|
||||||
public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
|
public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
|
/** Reset all breaker settings back to their defaults */
|
||||||
|
private void reset() {
|
||||||
|
logger.info("--> resetting breaker settings");
|
||||||
|
Settings resetSettings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING,
|
||||||
|
HierarchyCircuitBreakerService.DEFAULT_FIELDDATA_BREAKER_LIMIT)
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING,
|
||||||
|
HierarchyCircuitBreakerService.DEFAULT_FIELDDATA_OVERHEAD_CONSTANT)
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING,
|
||||||
|
HierarchyCircuitBreakerService.DEFAULT_REQUEST_BREAKER_LIMIT)
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0)
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_TYPE_SETTING,
|
||||||
|
HierarchyCircuitBreakerService.DEFAULT_BREAKER_TYPE)
|
||||||
|
.build();
|
||||||
|
client().admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void teardown() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
private String randomRidiculouslySmallLimit() {
|
private String randomRidiculouslySmallLimit() {
|
||||||
// 3 different ways to say 100 bytes
|
|
||||||
return randomFrom(Arrays.asList("100b", "100"));
|
return randomFrom(Arrays.asList("100b", "100"));
|
||||||
//, (10000. / JvmInfo.jvmInfo().getMem().getHeapMax().bytes()) + "%")); // this is prone to rounding errors and will fail if JVM memory changes!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestLogging("org.elasticsearch.indices.memory.breaker:TRACE,org.elasticsearch.index.fielddata:TRACE,org.elasticsearch.common.breaker:TRACE")
|
//@TestLogging("indices.breaker:TRACE,index.fielddata:TRACE,common.breaker:TRACE")
|
||||||
public void testMemoryBreaker() {
|
public void testMemoryBreaker() throws Exception {
|
||||||
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
||||||
final Client client = client();
|
final Client client = client();
|
||||||
|
|
||||||
try {
|
// index some different terms so we have some field data for loading
|
||||||
// index some different terms so we have some field data for loading
|
int docCount = scaledRandomIntBetween(300, 1000);
|
||||||
int docCount = scaledRandomIntBetween(300, 1000);
|
List<IndexRequestBuilder> reqs = newArrayList();
|
||||||
for (long id = 0; id < docCount; id++) {
|
for (long id = 0; id < docCount; id++) {
|
||||||
client.prepareIndex("cb-test", "type", Long.toString(id))
|
reqs.add(client.prepareIndex("cb-test", "type", Long.toString(id)).setSource("test", "value" + id));
|
||||||
.setSource(MapBuilder.<String, Object>newMapBuilder().put("test", "value" + id).map()).execute().actionGet();
|
|
||||||
}
|
|
||||||
|
|
||||||
// refresh
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// execute a search that loads field data (sorting on the "test" field)
|
|
||||||
client.prepareSearch("cb-test").setSource("{\"sort\": \"test\",\"query\":{\"match_all\":{}}}")
|
|
||||||
.execute().actionGet();
|
|
||||||
|
|
||||||
// clear field data cache (thus setting the loaded field data back to 0)
|
|
||||||
client.admin().indices().prepareClearCache("cb-test").setFieldDataCache(true).execute().actionGet();
|
|
||||||
|
|
||||||
// Update circuit breaker settings
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, randomRidiculouslySmallLimit())
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.05)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
|
|
||||||
|
|
||||||
// execute a search that loads field data (sorting on the "test" field)
|
|
||||||
// again, this time it should trip the breaker
|
|
||||||
assertFailures(client.prepareSearch("cb-test").setSource("{\"sort\": \"test\",\"query\":{\"match_all\":{}}}"),
|
|
||||||
RestStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
containsString("Data too large, data for [test] would be larger than limit of [100/100b]"));
|
|
||||||
|
|
||||||
NodesStatsResponse stats = client.admin().cluster().prepareNodesStats().setBreaker(true).get();
|
|
||||||
int breaks = 0;
|
|
||||||
for (NodeStats stat : stats.getNodes()) {
|
|
||||||
CircuitBreakerStats breakerStats = stat.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA);
|
|
||||||
breaks += breakerStats.getTrippedCount();
|
|
||||||
}
|
|
||||||
assertThat(breaks, greaterThanOrEqualTo(1));
|
|
||||||
} finally {
|
|
||||||
// Reset settings
|
|
||||||
Settings resetSettings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "-1")
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING,
|
|
||||||
HierarchyCircuitBreakerService.DEFAULT_FIELDDATA_OVERHEAD_CONSTANT)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
|
||||||
}
|
}
|
||||||
|
indexRandom(true, false, true, reqs);
|
||||||
|
|
||||||
|
// execute a search that loads field data (sorting on the "test" field)
|
||||||
|
SearchRequestBuilder searchRequest = client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC);
|
||||||
|
searchRequest.get();
|
||||||
|
|
||||||
|
// clear field data cache (thus setting the loaded field data back to 0)
|
||||||
|
client.admin().indices().prepareClearCache("cb-test").setFieldDataCache(true).execute().actionGet();
|
||||||
|
|
||||||
|
// Update circuit breaker settings
|
||||||
|
Settings settings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, randomRidiculouslySmallLimit())
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.05)
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
|
||||||
|
|
||||||
|
// execute a search that loads field data (sorting on the "test" field)
|
||||||
|
// again, this time it should trip the breaker
|
||||||
|
assertFailures(searchRequest, RestStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
containsString("Data too large, data for [test] would be larger than limit of [100/100b]"));
|
||||||
|
|
||||||
|
NodesStatsResponse stats = client.admin().cluster().prepareNodesStats().setBreaker(true).get();
|
||||||
|
int breaks = 0;
|
||||||
|
for (NodeStats stat : stats.getNodes()) {
|
||||||
|
CircuitBreakerStats breakerStats = stat.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA);
|
||||||
|
breaks += breakerStats.getTrippedCount();
|
||||||
|
}
|
||||||
|
assertThat(breaks, greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestLogging("org.elasticsearch.indices.memory.breaker:TRACE,org.elasticsearch.index.fielddata:TRACE,org.elasticsearch.common.breaker:TRACE")
|
public void testRamAccountingTermsEnum() throws Exception {
|
||||||
public void testRamAccountingTermsEnum() {
|
|
||||||
final Client client = client();
|
final Client client = client();
|
||||||
|
|
||||||
try {
|
// Create an index where the mappings have a field data filter
|
||||||
// Create an index where the mappings have a field data filter
|
assertAcked(prepareCreate("ramtest").setSource("{\"mappings\": {\"type\": {\"properties\": {\"test\": " +
|
||||||
assertAcked(prepareCreate("ramtest").setSource("{\"mappings\": {\"type\": {\"properties\": {\"test\": " +
|
"{\"type\": \"string\",\"fielddata\": {\"filter\": {\"regex\": {\"pattern\": \"^value.*\"}}}}}}}}"));
|
||||||
"{\"type\": \"string\",\"fielddata\": {\"filter\": {\"regex\": {\"pattern\": \"^value.*\"}}}}}}}}"));
|
|
||||||
|
|
||||||
// Wait 10 seconds for green
|
ensureGreen(TimeValue.timeValueSeconds(10), "ramtest");
|
||||||
client.admin().cluster().prepareHealth("ramtest").setWaitForGreenStatus().setTimeout("10s").execute().actionGet();
|
|
||||||
|
|
||||||
// index some different terms so we have some field data for loading
|
// index some different terms so we have some field data for loading
|
||||||
int docCount = scaledRandomIntBetween(300, 1000);
|
int docCount = scaledRandomIntBetween(300, 1000);
|
||||||
for (long id = 0; id < docCount; id++) {
|
List<IndexRequestBuilder> reqs = newArrayList();
|
||||||
client.prepareIndex("ramtest", "type", Long.toString(id))
|
for (long id = 0; id < docCount; id++) {
|
||||||
.setSource(MapBuilder.<String, Object>newMapBuilder().put("test", "value" + id).map()).execute().actionGet();
|
reqs.add(client.prepareIndex("ramtest", "type", Long.toString(id)).setSource("test", "value" + id));
|
||||||
}
|
|
||||||
|
|
||||||
// refresh
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// execute a search that loads field data (sorting on the "test" field)
|
|
||||||
client.prepareSearch("ramtest").setSource("{\"sort\": \"test\",\"query\":{\"match_all\":{}}}")
|
|
||||||
.execute().actionGet();
|
|
||||||
|
|
||||||
// clear field data cache (thus setting the loaded field data back to 0)
|
|
||||||
client.admin().indices().prepareClearCache("ramtest").setFieldDataCache(true).execute().actionGet();
|
|
||||||
|
|
||||||
// Update circuit breaker settings
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, randomRidiculouslySmallLimit())
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.05)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
|
|
||||||
|
|
||||||
// execute a search that loads field data (sorting on the "test" field)
|
|
||||||
// again, this time it should trip the breaker
|
|
||||||
assertFailures(client.prepareSearch("ramtest").setSource("{\"sort\": \"test\",\"query\":{\"match_all\":{}}}"),
|
|
||||||
RestStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
containsString("Data too large, data for [test] would be larger than limit of [100/100b]"));
|
|
||||||
|
|
||||||
NodesStatsResponse stats = client.admin().cluster().prepareNodesStats().setBreaker(true).get();
|
|
||||||
int breaks = 0;
|
|
||||||
for (NodeStats stat : stats.getNodes()) {
|
|
||||||
CircuitBreakerStats breakerStats = stat.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA);
|
|
||||||
breaks += breakerStats.getTrippedCount();
|
|
||||||
}
|
|
||||||
assertThat(breaks, greaterThanOrEqualTo(1));
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
// Reset settings
|
|
||||||
Settings resetSettings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "-1")
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING,
|
|
||||||
HierarchyCircuitBreakerService.DEFAULT_FIELDDATA_OVERHEAD_CONSTANT)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
|
||||||
}
|
}
|
||||||
|
indexRandom(true, reqs);
|
||||||
|
|
||||||
|
// execute a search that loads field data (sorting on the "test" field)
|
||||||
|
client.prepareSearch("ramtest").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC).get();
|
||||||
|
|
||||||
|
// clear field data cache (thus setting the loaded field data back to 0)
|
||||||
|
client.admin().indices().prepareClearCache("ramtest").setFieldDataCache(true).execute().actionGet();
|
||||||
|
|
||||||
|
// Update circuit breaker settings
|
||||||
|
Settings settings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, randomRidiculouslySmallLimit())
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.05)
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
|
||||||
|
|
||||||
|
// execute a search that loads field data (sorting on the "test" field)
|
||||||
|
// again, this time it should trip the breaker
|
||||||
|
assertFailures(client.prepareSearch("ramtest").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC),
|
||||||
|
RestStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
containsString("Data too large, data for [test] would be larger than limit of [100/100b]"));
|
||||||
|
|
||||||
|
NodesStatsResponse stats = client.admin().cluster().prepareNodesStats().setBreaker(true).get();
|
||||||
|
int breaks = 0;
|
||||||
|
for (NodeStats stat : stats.getNodes()) {
|
||||||
|
CircuitBreakerStats breakerStats = stat.getBreaker().getStats(CircuitBreaker.Name.FIELDDATA);
|
||||||
|
breaks += breakerStats.getTrippedCount();
|
||||||
|
}
|
||||||
|
assertThat(breaks, greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,108 +183,127 @@ public class CircuitBreakerServiceTests extends ElasticsearchIntegrationTest {
|
|||||||
* this case, the fielddata breaker borrows space from the request breaker
|
* this case, the fielddata breaker borrows space from the request breaker
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@TestLogging("org.elasticsearch.indices.memory.breaker:TRACE,org.elasticsearch.index.fielddata:TRACE,org.elasticsearch.common.breaker:TRACE")
|
public void testParentChecking() throws Exception {
|
||||||
public void testParentChecking() {
|
|
||||||
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
||||||
Client client = client();
|
Client client = client();
|
||||||
|
|
||||||
|
// index some different terms so we have some field data for loading
|
||||||
|
int docCount = scaledRandomIntBetween(300, 1000);
|
||||||
|
List<IndexRequestBuilder> reqs = newArrayList();
|
||||||
|
for (long id = 0; id < docCount; id++) {
|
||||||
|
reqs.add(client.prepareIndex("cb-test", "type", Long.toString(id)).setSource("test", "value" + id));
|
||||||
|
}
|
||||||
|
indexRandom(true, reqs);
|
||||||
|
|
||||||
|
// We need the request limit beforehand, just from a single node because the limit should always be the same
|
||||||
|
long beforeReqLimit = client.admin().cluster().prepareNodesStats().setBreaker(true).get()
|
||||||
|
.getNodes()[0].getBreaker().getStats(CircuitBreaker.Name.REQUEST).getLimit();
|
||||||
|
|
||||||
|
Settings resetSettings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "10b")
|
||||||
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0)
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
|
||||||
|
// Perform a search to load field data for the "test" field
|
||||||
try {
|
try {
|
||||||
// index some different terms so we have some field data for loading
|
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC).get();
|
||||||
int docCount = scaledRandomIntBetween(300, 1000);
|
fail("should have thrown an exception");
|
||||||
for (long id = 0; id < docCount; id++) {
|
} catch (Exception e) {
|
||||||
client.prepareIndex("cb-test", "type", Long.toString(id))
|
String errMsg = "[FIELDDATA] Data too large, data for [test] would be larger than limit of [10/10b]";
|
||||||
.setSource(MapBuilder.<String, Object>newMapBuilder().put("test", "value" + id).map()).execute().actionGet();
|
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
||||||
}
|
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
||||||
refresh();
|
}
|
||||||
|
|
||||||
// We need the request limit beforehand, just from a single node because the limit should always be the same
|
assertFailures(client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC),
|
||||||
long beforeReqLimit = client.admin().cluster().prepareNodesStats().setBreaker(true).get()
|
RestStatus.INTERNAL_SERVER_ERROR,
|
||||||
.getNodes()[0].getBreaker().getStats(CircuitBreaker.Name.REQUEST).getLimit();
|
containsString("Data too large, data for [test] would be larger than limit of [10/10b]"));
|
||||||
|
|
||||||
Settings resetSettings = settingsBuilder()
|
// Adjust settings so the parent breaker will fail, but the fielddata breaker doesn't
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "10b")
|
resetSettings = settingsBuilder()
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0)
|
.put(HierarchyCircuitBreakerService.TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, "15b")
|
||||||
.build();
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "90%")
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0)
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
|
||||||
// Perform a search to load field data for the "test" field
|
// Perform a search to load field data for the "test" field
|
||||||
try {
|
try {
|
||||||
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC).get();
|
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC).get();
|
||||||
} catch (Exception e) {
|
fail("should have thrown an exception");
|
||||||
String errMsg = "[FIELDDATA] Data too large, data for [test] would be larger than limit of [10/10b]";
|
} catch (Exception e) {
|
||||||
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
String errMsg = "[PARENT] Data too large, data for [test] would be larger than limit of [15/15b]";
|
||||||
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
||||||
}
|
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
||||||
|
|
||||||
assertFailures(client.prepareSearch("cb-test").setSource("{\"sort\": \"test\",\"query\":{\"match_all\":{}}}"),
|
|
||||||
RestStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
containsString("Data too large, data for [test] would be larger than limit of [10/10b]"));
|
|
||||||
|
|
||||||
// Adjust settings so the parent breaker will fail, but the fielddata breaker doesn't
|
|
||||||
resetSettings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING, "15b")
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "90%")
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING, 1.0)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
|
||||||
|
|
||||||
// Perform a search to load field data for the "test" field
|
|
||||||
try {
|
|
||||||
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addSort("test", SortOrder.DESC).get();
|
|
||||||
} catch (Exception e) {
|
|
||||||
String errMsg = "[PARENT] Data too large, data for [test] would be larger than limit of [15/15b]";
|
|
||||||
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
|
||||||
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
Settings resetSettings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING, "-1")
|
|
||||||
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, HierarchyCircuitBreakerService.DEFAULT_REQUEST_BREAKER_LIMIT)
|
|
||||||
.put(HierarchyCircuitBreakerService.FIELDDATA_CIRCUIT_BREAKER_OVERHEAD_SETTING,
|
|
||||||
HierarchyCircuitBreakerService.DEFAULT_FIELDDATA_OVERHEAD_CONSTANT)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestLogging("org.elasticsearch.indices.memory.breaker:TRACE,org.elasticsearch.index.fielddata:TRACE,org.elasticsearch.common.breaker:TRACE")
|
public void testRequestBreaker() throws Exception {
|
||||||
public void testRequestBreaker() {
|
|
||||||
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
||||||
Client client = client();
|
Client client = client();
|
||||||
|
|
||||||
|
// Make request breaker limited to a small amount
|
||||||
|
Settings resetSettings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, "10b")
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
|
||||||
|
// index some different terms so we have some field data for loading
|
||||||
|
int docCount = scaledRandomIntBetween(300, 1000);
|
||||||
|
List<IndexRequestBuilder> reqs = newArrayList();
|
||||||
|
for (long id = 0; id < docCount; id++) {
|
||||||
|
reqs.add(client.prepareIndex("cb-test", "type", Long.toString(id)).setSource("test", id));
|
||||||
|
}
|
||||||
|
indexRandom(true, reqs);
|
||||||
|
|
||||||
|
// A cardinality aggregation uses BigArrays and thus the REQUEST breaker
|
||||||
try {
|
try {
|
||||||
// Make request breaker limited to a small amount
|
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addAggregation(cardinality("card").field("test")).get();
|
||||||
Settings resetSettings = settingsBuilder()
|
fail("aggregation should have tripped the breaker");
|
||||||
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, "10b")
|
} catch (Exception e) {
|
||||||
.build();
|
String errMsg = "CircuitBreakingException[[REQUEST] Data too large, data for [<reused_arrays>] would be larger than limit of [10/10b]]";
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
||||||
|
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
||||||
// index some different terms so we have some field data for loading
|
|
||||||
int docCount = scaledRandomIntBetween(300, 1000);
|
|
||||||
for (long id = 0; id < docCount; id++) {
|
|
||||||
client.prepareIndex("cb-test", "type", Long.toString(id))
|
|
||||||
.setSource(MapBuilder.<String, Object>newMapBuilder().put("test", id).map()).execute().actionGet();
|
|
||||||
}
|
|
||||||
refresh();
|
|
||||||
|
|
||||||
// A cardinality aggregation uses BigArrays and thus the REQUEST breaker
|
|
||||||
try {
|
|
||||||
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addAggregation(cardinality("card").field("test")).get();
|
|
||||||
fail("aggregation should have tripped the breaker");
|
|
||||||
} catch (Exception e) {
|
|
||||||
String errMsg = "CircuitBreakingException[[REQUEST] Data too large, data for [<reused_arrays>] would be larger than limit of [10/10b]]";
|
|
||||||
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
|
||||||
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
Settings resetSettings = settingsBuilder()
|
|
||||||
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING,
|
|
||||||
HierarchyCircuitBreakerService.DEFAULT_REQUEST_BREAKER_LIMIT)
|
|
||||||
.build();
|
|
||||||
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoopRequestBreaker() throws Exception {
|
||||||
|
assertAcked(prepareCreate("cb-test", 1, settingsBuilder().put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))));
|
||||||
|
Client client = client();
|
||||||
|
|
||||||
|
// Make request breaker limited to a small amount
|
||||||
|
Settings resetSettings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_LIMIT_SETTING, "10b")
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
|
||||||
|
// index some different terms so we have some field data for loading
|
||||||
|
int docCount = scaledRandomIntBetween(300, 1000);
|
||||||
|
List<IndexRequestBuilder> reqs = newArrayList();
|
||||||
|
for (long id = 0; id < docCount; id++) {
|
||||||
|
reqs.add(client.prepareIndex("cb-test", "type", Long.toString(id)).setSource("test", id));
|
||||||
|
}
|
||||||
|
indexRandom(true, reqs);
|
||||||
|
|
||||||
|
// A cardinality aggregation uses BigArrays and thus the REQUEST breaker
|
||||||
|
try {
|
||||||
|
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addAggregation(cardinality("card").field("test")).get();
|
||||||
|
fail("aggregation should have tripped the breaker");
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errMsg = "CircuitBreakingException[[REQUEST] Data too large, data for [<reused_arrays>] would be larger than limit of [10/10b]]";
|
||||||
|
assertThat("Exception: " + ExceptionsHelper.unwrapCause(e) + " should contain a CircuitBreakingException",
|
||||||
|
ExceptionsHelper.unwrapCause(e).getMessage().contains(errMsg), equalTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make request breaker into a noop breaker
|
||||||
|
resetSettings = settingsBuilder()
|
||||||
|
.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_TYPE_SETTING, "noop")
|
||||||
|
.build();
|
||||||
|
client.admin().cluster().prepareUpdateSettings().setTransientSettings(resetSettings).execute().actionGet();
|
||||||
|
|
||||||
|
// A cardinality aggregation uses BigArrays and thus the REQUEST breaker
|
||||||
|
client.prepareSearch("cb-test").setQuery(matchAllQuery()).addAggregation(cardinality("card").field("test")).get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ import org.elasticsearch.cluster.metadata.MetaData;
|
|||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.Priority;
|
import org.elasticsearch.common.Priority;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.breaker.CircuitBreaker;
|
||||||
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
import org.elasticsearch.common.collect.ImmutableOpenMap;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
@ -90,6 +91,7 @@ import org.elasticsearch.index.translog.TranslogService;
|
|||||||
import org.elasticsearch.index.translog.fs.FsTranslog;
|
import org.elasticsearch.index.translog.fs.FsTranslog;
|
||||||
import org.elasticsearch.index.translog.fs.FsTranslogFile;
|
import org.elasticsearch.index.translog.fs.FsTranslogFile;
|
||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
|
import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
|
||||||
import org.elasticsearch.indices.cache.query.IndicesQueryCache;
|
import org.elasticsearch.indices.cache.query.IndicesQueryCache;
|
||||||
import org.elasticsearch.indices.recovery.RecoverySettings;
|
import org.elasticsearch.indices.recovery.RecoverySettings;
|
||||||
import org.elasticsearch.indices.store.IndicesStore;
|
import org.elasticsearch.indices.store.IndicesStore;
|
||||||
@ -447,11 +449,20 @@ public abstract class ElasticsearchIntegrationTest extends ElasticsearchTestCase
|
|||||||
return compatibilityVersion().onOrAfter(Version.V_1_1_0);
|
return compatibilityVersion().onOrAfter(Version.V_1_1_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Rarely set the request breaker to a Noop breaker */
|
||||||
|
protected static void setRandomBreakerSettings(Random random, ImmutableSettings.Builder builder) {
|
||||||
|
// Rarely
|
||||||
|
if (RandomInts.randomInt(random, 100) >= 90) {
|
||||||
|
builder.put(HierarchyCircuitBreakerService.REQUEST_CIRCUIT_BREAKER_TYPE_SETTING, CircuitBreaker.Type.NOOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static ImmutableSettings.Builder setRandomSettings(Random random, ImmutableSettings.Builder builder) {
|
private static ImmutableSettings.Builder setRandomSettings(Random random, ImmutableSettings.Builder builder) {
|
||||||
setRandomMerge(random, builder);
|
setRandomMerge(random, builder);
|
||||||
setRandomTranslogSettings(random, builder);
|
setRandomTranslogSettings(random, builder);
|
||||||
setRandomNormsLoading(random, builder);
|
setRandomNormsLoading(random, builder);
|
||||||
setRandomScriptingSettings(random, builder);
|
setRandomScriptingSettings(random, builder);
|
||||||
|
setRandomBreakerSettings(random, builder);
|
||||||
if (random.nextBoolean()) {
|
if (random.nextBoolean()) {
|
||||||
if (random.nextInt(10) == 0) { // do something crazy slow here
|
if (random.nextInt(10) == 0) { // do something crazy slow here
|
||||||
builder.put(IndicesStore.INDICES_STORE_THROTTLE_MAX_BYTES_PER_SEC, new ByteSizeValue(RandomInts.randomIntBetween(random, 1, 10), ByteSizeUnit.MB));
|
builder.put(IndicesStore.INDICES_STORE_THROTTLE_MAX_BYTES_PER_SEC, new ByteSizeValue(RandomInts.randomIntBetween(random, 1, 10), ByteSizeUnit.MB));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user