1919
2020package org .elasticsearch .cluster .routing .allocation ;
2121
22+ import java .util .HashSet ;
2223import java .util .Set ;
24+ import java .util .function .Supplier ;
2325
2426import com .carrotsearch .hppc .ObjectLookupContainer ;
2527import com .carrotsearch .hppc .cursors .ObjectObjectCursor ;
2628import org .elasticsearch .client .Client ;
2729import org .elasticsearch .cluster .ClusterInfo ;
28- import org .elasticsearch .cluster .ClusterInfoService ;
30+ import org .elasticsearch .cluster .ClusterState ;
2931import org .elasticsearch .cluster .DiskUsage ;
32+ import org .elasticsearch .cluster .block .ClusterBlockLevel ;
33+ import org .elasticsearch .cluster .metadata .IndexMetaData ;
34+ import org .elasticsearch .cluster .routing .RoutingNode ;
35+ import org .elasticsearch .cluster .routing .ShardRouting ;
3036import org .elasticsearch .common .Strings ;
3137import org .elasticsearch .common .collect .ImmutableOpenMap ;
3238import org .elasticsearch .common .component .AbstractComponent ;
33- import org .elasticsearch .common .inject .Inject ;
3439import org .elasticsearch .common .settings .ClusterSettings ;
3540import org .elasticsearch .common .settings .Settings ;
3641import org .elasticsearch .common .util .set .Sets ;
4045 * reroute if it does. Also responsible for logging about nodes that have
4146 * passed the disk watermarks
4247 */
43- public class DiskThresholdMonitor extends AbstractComponent implements ClusterInfoService . Listener {
48+ public class DiskThresholdMonitor extends AbstractComponent {
4449 private final DiskThresholdSettings diskThresholdSettings ;
4550 private final Client client ;
4651 private final Set <String > nodeHasPassedWatermark = Sets .newConcurrentHashSet ();
47-
52+ private final Supplier < ClusterState > clusterStateSupplier ;
4853 private long lastRunNS ;
4954
50- // TODO: remove injection when ClusterInfoService is not injected
51- @ Inject
52- public DiskThresholdMonitor (Settings settings , ClusterSettings clusterSettings ,
53- ClusterInfoService infoService , Client client ) {
55+ public DiskThresholdMonitor (Settings settings , Supplier <ClusterState > clusterStateSupplier , ClusterSettings clusterSettings ,
56+ Client client ) {
5457 super (settings );
58+ this .clusterStateSupplier = clusterStateSupplier ;
5559 this .diskThresholdSettings = new DiskThresholdSettings (settings , clusterSettings );
5660 this .client = client ;
57- infoService .addListener (this );
5861 }
5962
6063 /**
6164 * Warn about the given disk usage if the low or high watermark has been passed
6265 */
6366 private void warnAboutDiskIfNeeded (DiskUsage usage ) {
6467 // Check absolute disk values
65- if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdHigh ().getBytes ()) {
68+ if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdFloodStage ().getBytes ()) {
69+ logger .warn ("floodstage disk watermark [{}] exceeded on {}, all indices on this node will marked read-only" ,
70+ diskThresholdSettings .getFreeBytesThresholdFloodStage (), usage );
71+ } else if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdHigh ().getBytes ()) {
6672 logger .warn ("high disk watermark [{}] exceeded on {}, shards will be relocated away from this node" ,
6773 diskThresholdSettings .getFreeBytesThresholdHigh (), usage );
6874 } else if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdLow ().getBytes ()) {
@@ -72,6 +78,9 @@ private void warnAboutDiskIfNeeded(DiskUsage usage) {
7278
7379 // Check percentage disk values
7480 if (usage .getFreeDiskAsPercentage () < diskThresholdSettings .getFreeDiskThresholdHigh ()) {
81+ logger .warn ("floodstage disk watermark [{}] exceeded on {}, all indices on this node will marked read-only" ,
82+ Strings .format1Decimals (100.0 - diskThresholdSettings .getFreeDiskThresholdFloodStage (), "%" ), usage );
83+ } else if (usage .getFreeDiskAsPercentage () < diskThresholdSettings .getFreeDiskThresholdHigh ()) {
7584 logger .warn ("high disk watermark [{}] exceeded on {}, shards will be relocated away from this node" ,
7685 Strings .format1Decimals (100.0 - diskThresholdSettings .getFreeDiskThresholdHigh (), "%" ), usage );
7786 } else if (usage .getFreeDiskAsPercentage () < diskThresholdSettings .getFreeDiskThresholdLow ()) {
@@ -80,7 +89,7 @@ private void warnAboutDiskIfNeeded(DiskUsage usage) {
8089 }
8190 }
8291
83- @ Override
92+
8493 public void onNewInfo (ClusterInfo info ) {
8594 ImmutableOpenMap <String , DiskUsage > usages = info .getNodeLeastAvailableDiskUsages ();
8695 if (usages != null ) {
@@ -95,12 +104,21 @@ public void onNewInfo(ClusterInfo info) {
95104 nodeHasPassedWatermark .remove (node );
96105 }
97106 }
98-
107+ ClusterState state = clusterStateSupplier .get ();
108+ Set <String > indicesToMarkReadOnly = new HashSet <>();
99109 for (ObjectObjectCursor <String , DiskUsage > entry : usages ) {
100110 String node = entry .key ;
101111 DiskUsage usage = entry .value ;
102112 warnAboutDiskIfNeeded (usage );
103- if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdHigh ().getBytes () ||
113+ if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdFloodStage ().getBytes () ||
114+ usage .getFreeDiskAsPercentage () < diskThresholdSettings .getFreeDiskThresholdFloodStage ()) {
115+ RoutingNode routingNode = state .getRoutingNodes ().node (node );
116+ if (routingNode != null ) { // this might happen if we haven't got the full cluster-state yet?!
117+ for (ShardRouting routing : routingNode ) {
118+ indicesToMarkReadOnly .add (routing .index ().getName ());
119+ }
120+ }
121+ } else if (usage .getFreeBytes () < diskThresholdSettings .getFreeBytesThresholdHigh ().getBytes () ||
104122 usage .getFreeDiskAsPercentage () < diskThresholdSettings .getFreeDiskThresholdHigh ()) {
105123 if ((System .nanoTime () - lastRunNS ) > diskThresholdSettings .getRerouteInterval ().nanos ()) {
106124 lastRunNS = System .nanoTime ();
@@ -136,9 +154,23 @@ public void onNewInfo(ClusterInfo info) {
136154 }
137155 if (reroute ) {
138156 logger .info ("rerouting shards: [{}]" , explanation );
139- // Execute an empty reroute, but don't block on the response
140- client .admin ().cluster ().prepareReroute ().execute ();
157+ reroute ();
158+ }
159+ indicesToMarkReadOnly .removeIf (index -> state .getBlocks ().indexBlocked (ClusterBlockLevel .WRITE , index ));
160+ if (indicesToMarkReadOnly .isEmpty () == false ) {
161+ markIndicesReadOnly (indicesToMarkReadOnly );
141162 }
142163 }
143164 }
165+
166+ protected void markIndicesReadOnly (Set <String > indicesToMarkReadOnly ) {
167+ // set read-only block but don't block on the response
168+ client .admin ().indices ().prepareUpdateSettings (indicesToMarkReadOnly .toArray (Strings .EMPTY_ARRAY )).
169+ setSettings (Settings .builder ().put (IndexMetaData .SETTING_READ_ONLY_ALLOW_DELETE , true ).build ()).execute ();
170+ }
171+
172+ protected void reroute () {
173+ // Execute an empty reroute, but don't block on the response
174+ client .admin ().cluster ().prepareReroute ().execute ();
175+ }
144176}
0 commit comments