blob: c898c08d648223836f2649114b0d0b75cf7fba75 [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.config;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static org.apache.cassandra.config.DataRateSpec.DataRateUnit.MEBIBYTES_PER_SECOND;
/**
* Converters for backward compatibility with the old cassandra.yaml where duration, data rate and
* data storage configuration parameters were provided only by value and the expected unit was part of the configuration
* parameter name(suffix). (CASSANDRA-15234)
* It is important to be noted that this converter is not intended to be used when we don't change name of a configuration
* parameter but we want to add unit. This would always default to the old value provided without a unit at the moment.
* In case this functionality is needed at some point, please, raise a Jira ticket. There is only one exception handling
* three parameters (key_cache_save_period, row_cache_save_period, counter_cache_save_period) - the SECONDS_CUSTOM_DURATION
* converter.
*/
public enum Converters
{
/**
* This converter is used when we change the name of a cassandra.yaml configuration parameter but we want to be
* able to still use the old name too. No units involved.
*/
IDENTITY(null, null, o -> o, o -> o),
MILLIS_DURATION_LONG(Long.class, DurationSpec.LongMillisecondsBound.class,
DurationSpec.LongMillisecondsBound::new,
o -> o == null ? null : o.toMilliseconds()),
MILLIS_DURATION_INT(Integer.class, DurationSpec.IntMillisecondsBound.class,
DurationSpec.IntMillisecondsBound::new,
o -> o == null ? null : o.toMilliseconds()),
MILLIS_DURATION_DOUBLE(Double.class, DurationSpec.IntMillisecondsBound.class,
o -> Double.isNaN(o) ? new DurationSpec.IntMillisecondsBound(0) :
new DurationSpec.IntMillisecondsBound(o, TimeUnit.MILLISECONDS),
o -> (double) o.toMilliseconds()),
/**
* This converter is used to support backward compatibility for parameters where in the past -1 was used as a value
* Example: credentials_update_interval_in_ms = -1 and credentials_update_interval = null are equal.
*/
MILLIS_CUSTOM_DURATION(Integer.class, DurationSpec.IntMillisecondsBound.class,
o -> o == -1 ? null : new DurationSpec.IntMillisecondsBound(o),
o -> o == null ? -1 : o.toMilliseconds()),
SECONDS_DURATION(Integer.class, DurationSpec.IntSecondsBound.class,
DurationSpec.IntSecondsBound::new,
o -> o == null ? null : o.toSeconds()),
NEGATIVE_SECONDS_DURATION(Integer.class, DurationSpec.IntSecondsBound.class,
o -> o < 0 ? new DurationSpec.IntSecondsBound(0) : new DurationSpec.IntSecondsBound(o),
o -> o == null ? null : o.toSeconds()),
/**
* This converter is used to support backward compatibility for Duration parameters where we added the opportunity
* for the users to add a unit in the parameters' values but we didn't change the names. (key_cache_save_period,
* row_cache_save_period, counter_cache_save_period)
* Example: row_cache_save_period = 0 and row_cache_save_period = 0s (quantity of 0s) are equal.
*/
SECONDS_CUSTOM_DURATION(String.class, DurationSpec.IntSecondsBound.class,
DurationSpec.IntSecondsBound::inSecondsString,
o -> o == null ? null : Long.toString(o.toSeconds())),
/**
* This converter is used to support backward compatibility for parameters where in the past -1 was used as a value
* Example: index_summary_resize_interval_in_minutes = -1 and index_summary_resize_interval = null are equal.
*/
MINUTES_CUSTOM_DURATION(Integer.class, DurationSpec.IntMinutesBound.class,
o -> o == -1 ? null : new DurationSpec.IntMinutesBound(o),
o -> o == null ? -1 : o.toMinutes()),
MEBIBYTES_DATA_STORAGE_LONG(Long.class, DataStorageSpec.LongMebibytesBound.class,
DataStorageSpec.LongMebibytesBound::new,
o -> o == null ? null : o.toMebibytes()),
MEBIBYTES_DATA_STORAGE_INT(Integer.class, DataStorageSpec.IntMebibytesBound.class,
DataStorageSpec.IntMebibytesBound::new,
o -> o == null ? null : o.toMebibytes()),
NEGATIVE_MEBIBYTES_DATA_STORAGE_INT(Integer.class, DataStorageSpec.IntMebibytesBound.class,
o -> o < 0 ? null : new DataStorageSpec.IntMebibytesBound(o),
o -> o == null ? -1 : o.toMebibytes()),
KIBIBYTES_DATASTORAGE(Integer.class, DataStorageSpec.IntKibibytesBound.class,
DataStorageSpec.IntKibibytesBound::new,
o -> o == null ? null : o.toKibibytes()),
BYTES_DATASTORAGE(Integer.class, DataStorageSpec.IntBytesBound.class,
DataStorageSpec.IntBytesBound::new,
o -> o == null ? null : o.toBytes()),
/**
* This converter is used to support backward compatibility for parameters where in the past negative number was used as a value
* Example: native_transport_max_concurrent_requests_in_bytes_per_ip = -1 and native_transport_max_request_data_in_flight_per_ip = null
* are equal. All negative numbers are printed as 0 in virtual tables.
*/
BYTES_CUSTOM_DATASTORAGE(Long.class, DataStorageSpec.LongBytesBound.class,
o -> o == -1 ? null : new DataStorageSpec.LongBytesBound(o),
o -> o == null ? null : o.toBytes()),
MEBIBYTES_PER_SECOND_DATA_RATE(Integer.class, DataRateSpec.LongBytesPerSecondBound.class,
i -> new DataRateSpec.LongBytesPerSecondBound(i, MEBIBYTES_PER_SECOND),
o -> o == null ? null : o.toMebibytesPerSecondAsInt()),
/**
* This converter is a custom one to support backward compatibility for stream_throughput_outbound and
* inter_dc_stream_throughput_outbound which were provided in megabits per second prior CASSANDRA-15234.
*/
MEGABITS_TO_BYTES_PER_SECOND_DATA_RATE(Integer.class, DataRateSpec.LongBytesPerSecondBound.class,
i -> DataRateSpec.LongBytesPerSecondBound.megabitsPerSecondInBytesPerSecond(i),
o -> o == null ? null : o.toMegabitsPerSecondAsInt());
private final Class<?> oldType;
private final Class<?> newType;
private final Function<Object, Object> convert;
private final Function<Object, Object> reverseConvert;
<Old, New> Converters(Class<Old> oldType, Class<New> newType, Function<Old, New> convert, Function<New, Old> reverseConvert)
{
this.oldType = oldType;
this.newType = newType;
this.convert = (Function<Object, Object>) convert;
this.reverseConvert = (Function<Object, Object>) reverseConvert;
}
/**
* A method to identify what type is needed to be returned by the converter used for a configuration parameter
* in {@link Replaces} annotation in {@link Config}
*
* @return class type
*/
public Class<?> getOldType()
{
return oldType;
}
/**
* Expected return type from {@link #convert(Object)}, and input type to {@link #unconvert(Object)}
*
* @return type that {@link #convert(Object)} is expected to return
*/
public Class<?> getNewType()
{
return newType;
}
/**
* Apply the converter specified as part of the {@link Replaces} annotation in {@link Config}
*
* @param value we will use from cassandra.yaml to create a new {@link Config} parameter of type {@link DurationSpec},
* {@link DataRateSpec} or {@link DataStorageSpec}
* @return new object of type {@link DurationSpec}, {@link DataRateSpec} or {@link DataStorageSpec}
*/
public Object convert(Object value)
{
if (value == null) return null;
return convert.apply(value);
}
/**
* Apply the converter specified as part of the {@link Replaces} annotation in {@link Config} to get config parameters'
* values in the old format pre-CASSANDRA-15234 and in the right units, used in the Virtual Tables to ensure backward
* compatibility
*
* @param value we will use to calculate the output value
* @return the numeric value
*/
public Object unconvert(Object value)
{
return reverseConvert.apply(value);
}
}