blob: dde09be8ffdd70847b0d79ad562225d3fe02d5be [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.cassandra.db.guardrails;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import org.apache.cassandra.service.ClientState;
/**
* A guardrail that enables the use of a particular feature.
*
* <p>Note that this guardrail only aborts operations (if the feature is not enabled) so is only meant for query-based
* guardrails (we're happy to reject queries deemed dangerous, but we don't want to create a guardrail that breaks
* compaction for instance).
*/
public class EnableFlag extends Guardrail
{
private final Predicate<ClientState> warned;
private final Predicate<ClientState> enabled;
private final String featureName;
/**
* Creates a new {@link EnableFlag} guardrail.
*
* @param name the identifying name of the guardrail
* @param reason the optional description of the reason for guarding the operation
* @param enabled a {@link ClientState}-based supplier of boolean indicating whether the feature guarded by this
* guardrail is enabled.
* @param featureName The feature that is guarded by this guardrail (for reporting in error messages), {@link
* EnableFlag#ensureEnabled(String, ClientState)} can specify a different {@code featureName}.
*/
public EnableFlag(String name, @Nullable String reason, Predicate<ClientState> enabled, String featureName)
{
this(name, reason, (state) -> false, enabled, featureName);
}
/**
* Creates a new {@link EnableFlag} guardrail.
*
* @param name the identifying name of the guardrail
* @param reason the optional description of the reason for guarding the operation
* @param warned a {@link ClientState}-based supplier of boolean indicating whether warning should be
* emitted even guardrail as such has passed. If guardrail fails, the warning will not be
* emitted. This might be used for cases when we want to warn a user regardless of successful
* guardrail execution.
* @param enabled a {@link ClientState}-based supplier of boolean indicating whether the feature guarded by this
* guardrail is enabled.
* @param featureName The feature that is guarded by this guardrail (for reporting in error messages), {@link
* EnableFlag#ensureEnabled(String, ClientState)} can specify a different {@code featureName}.
*/
public EnableFlag(String name,
@Nullable String reason,
Predicate<ClientState> warned,
Predicate<ClientState> enabled,
String featureName)
{
super(name, reason);
this.warned = warned;
this.enabled = enabled;
this.featureName = featureName;
}
/**
* Returns whether the guarded feature is enabled or not.
*
* @param state The client state, used to skip the check if the query is internal or is done by a superuser.
* A {@code null} value means that the check should be done regardless of the query.
* @return {@code true} is the feature is enabled, {@code false} otherwise.
*/
public boolean isEnabled(@Nullable ClientState state)
{
return !enabled(state) || enabled.test(state);
}
/**
* Aborts the operation if this guardrail is not enabled.
*
* <p>This must be called when the feature guarded by this guardrail is used to ensure such use is in fact
* allowed.
*
* @param state The client state, used to skip the check if the query is internal or is done by a superuser.
* A {@code null} value means that the check should be done regardless of the query.
*/
public void ensureEnabled(@Nullable ClientState state)
{
ensureEnabled(featureName, state);
}
/**
* Aborts the operation if this guardrail is not enabled.
*
* <p>This must be called when the feature guarded by this guardrail is used to ensure such use is in fact
* allowed.
*
* @param featureName The feature that is guarded by this guardrail (for reporting in error messages).
* @param state The client state, used to skip the check if the query is internal or is done by a superuser. A
* {@code null} value means that the check should be done regardless of the query, although it
* won't throw any exception if the failure threshold is exceeded. This is so because checks
* without an associated client come from asynchronous processes such as compaction, and we don't
* want to interrupt such processes.
*/
public void ensureEnabled(String featureName, @Nullable ClientState state)
{
if (!enabled(state))
return;
if (!enabled.test(state))
{
fail(featureName + " is not allowed", state);
return;
}
if (warned.test(state))
warn(featureName + " is not recommended");
}
}