blob: bbe238f5f05add29a5a0e72bd40bce6e20971e9b [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.shardingsphere.sharding.algorithm.sharding.datetime;
import com.google.common.collect.Range;
import lombok.Getter;
import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
import org.apache.shardingsphere.infra.util.datetime.DateTimeFormatterFactory;
import org.apache.shardingsphere.sharding.algorithm.sharding.ShardingAutoTableAlgorithmUtils;
import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.apache.shardingsphere.sharding.exception.data.InvalidDatetimeFormatException;
import org.apache.shardingsphere.sharding.exception.data.NullShardingValueException;
import java.text.DecimalFormat;
import java.text.ParsePosition;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Properties;
/**
* Auto interval sharding algorithm.
*/
public final class AutoIntervalShardingAlgorithm implements StandardShardingAlgorithm<Comparable<?>>, ShardingAutoTableAlgorithm {
private static final String DATE_TIME_LOWER_KEY = "datetime-lower";
private static final String DATE_TIME_UPPER_KEY = "datetime-upper";
private static final String SHARDING_SECONDS_KEY = "sharding-seconds";
private LocalDateTime dateTimeLower;
private long shardingSeconds;
@Getter
private int autoTablesAmount;
@Override
public void init(final Properties props) {
dateTimeLower = getDateTime(props);
shardingSeconds = getShardingSeconds(props);
autoTablesAmount = (int) (Math.ceil((double) (parseDate(props.getProperty(DATE_TIME_UPPER_KEY)) / shardingSeconds)) + 2);
}
private LocalDateTime getDateTime(final Properties props) {
String value = props.getProperty(DATE_TIME_LOWER_KEY);
ShardingSpherePreconditions.checkNotNull(value, () -> new AlgorithmInitializationException(this, String.format("%s cannot be null.", DATE_TIME_LOWER_KEY)));
try {
return LocalDateTime.parse(value, DateTimeFormatterFactory.getStandardFormatter());
} catch (final DateTimeParseException ignored) {
throw new InvalidDatetimeFormatException(DATE_TIME_LOWER_KEY, value, "yyyy-MM-dd HH:mm:ss");
}
}
private long getShardingSeconds(final Properties props) {
ShardingSpherePreconditions.checkContainsKey(props, SHARDING_SECONDS_KEY, () -> new AlgorithmInitializationException(this, String.format("%s cannot be null.", SHARDING_SECONDS_KEY)));
return Long.parseLong(props.getProperty(SHARDING_SECONDS_KEY));
}
@Override
public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Comparable<?>> shardingValue) {
ShardingSpherePreconditions.checkNotNull(shardingValue.getValue(), NullShardingValueException::new);
String tableNameSuffix = String.valueOf(doSharding(parseDate(shardingValue.getValue())));
return ShardingAutoTableAlgorithmUtils.findMatchedTargetName(availableTargetNames, tableNameSuffix, shardingValue.getDataNodeInfo()).orElse(null);
}
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Comparable<?>> shardingValue) {
Collection<String> result = new LinkedHashSet<>(availableTargetNames.size(), 1F);
int firstPartition = getFirstPartition(shardingValue.getValueRange());
int lastPartition = getLastPartition(shardingValue.getValueRange());
for (int i = firstPartition; i <= lastPartition; i++) {
String suffix = String.valueOf(i);
ShardingAutoTableAlgorithmUtils.findMatchedTargetName(availableTargetNames, suffix, shardingValue.getDataNodeInfo()).ifPresent(result::add);
}
return result;
}
private int doSharding(final long shardingValue) {
String position = new DecimalFormat("0.00").format((double) shardingValue / shardingSeconds);
return Math.min(Math.max(0, (int) Math.ceil(Double.parseDouble(position))), autoTablesAmount - 1);
}
private int getFirstPartition(final Range<Comparable<?>> valueRange) {
return valueRange.hasLowerBound() ? doSharding(parseDate(valueRange.lowerEndpoint())) : 0;
}
private int getLastPartition(final Range<Comparable<?>> valueRange) {
return valueRange.hasUpperBound() ? doSharding(parseDate(valueRange.upperEndpoint())) : autoTablesAmount - 1;
}
private long parseDate(final Comparable<?> shardingValue) {
LocalDateTime dateValue = LocalDateTime.from(DateTimeFormatterFactory.getStandardFormatter().parse(shardingValue.toString(), new ParsePosition(0)));
return Duration.between(dateTimeLower, dateValue).toMillis() / 1000;
}
@Override
public String getType() {
return "AUTO_INTERVAL";
}
}