You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2022/07/14 14:14:58 UTC
[shardingsphere] branch master updated: Provide support for JSR-310 Year and Month in IntervalShardingAlgorithm (#19139)
This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 58dced0e9ca Provide support for JSR-310 Year and Month in IntervalShardingAlgorithm (#19139)
58dced0e9ca is described below
commit 58dced0e9ca1420b389ffef6bbb7c626254029a9
Author: Ling Hengqian <li...@outlook.com>
AuthorDate: Thu Jul 14 22:14:46 2022 +0800
Provide support for JSR-310 Year and Month in IntervalShardingAlgorithm (#19139)
* Provide support for JSR-310 Year and Month in IntervalShardingAlgorithm
* fix checkstyle.
* update doc for Interval Sharding Algorithm.
* Provide support for java.time.YearMonth in IntervalShardingAlgorithm.
* fix checkstyle again.
---
.../builtin-algorithm/sharding.cn.md | 2 +
.../builtin-algorithm/sharding.en.md | 2 +
.../datetime/IntervalShardingAlgorithm.java | 132 +++++++++++++++++++--
.../datetime/IntervalShardingAlgorithmTest.java | 93 +++++++++++++++
4 files changed, 216 insertions(+), 13 deletions(-)
diff --git a/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.cn.md b/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.cn.md
index ab7644191c1..89ac3d0edf3 100644
--- a/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.cn.md
+++ b/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.cn.md
@@ -86,6 +86,8 @@ Apache ShardingSphere 内置的标准分片算法实现类包括:
#### 时间范围分片算法
+当传入的分片键为 `java.time.Instant` 时存在特例处理,其会携带上系统的时区信息后转化为 `datetime-pattern` 的字符串格式, 再进行下一步分片。
+
类型:INTERVAL
可配置属性:
diff --git a/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.en.md b/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.en.md
index 011222416fe..4bdf853174c 100644
--- a/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.en.md
+++ b/docs/document/content/user-manual/shardingsphere-jdbc/builtin-algorithm/sharding.en.md
@@ -89,6 +89,8 @@ Attributes:
#### Interval Sharding Algorithm
+When the incoming sharding key is `java.time.Instant`, there is a special case, which will carry the time zone information of the system and convert it into the string format of `datetime-pattern`, and then proceed to the next sharding.
+
Type: INTERVAL
Attributes:
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
index 892af21ce0c..e5afee2d6eb 100644
--- a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
@@ -26,13 +26,17 @@ import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingV
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
-import java.time.ZoneId;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+import java.time.Month;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQueries;
@@ -138,12 +142,21 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
private Collection<String> doSharding(final Collection<String> availableTargetNames, final Range<Comparable<?>> range) {
TemporalAccessor calculateTime = dateTimeLower;
- LocalDate queryToLocalDate = calculateTime.query(TemporalQueries.localDate());
- LocalTime queryToLocalTime = calculateTime.query(TemporalQueries.localTime());
- if (null == queryToLocalTime) {
- return doShardingInLocalDate(availableTargetNames, range, calculateTime);
+ if (!calculateTime.isSupported(ChronoField.NANO_OF_DAY)) {
+ if (calculateTime.isSupported(ChronoField.EPOCH_DAY)) {
+ return doShardingInLocalDate(availableTargetNames, range, calculateTime);
+ }
+ if (calculateTime.isSupported(ChronoField.YEAR) && calculateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ return doShardingInYearMonth(availableTargetNames, range, calculateTime);
+ }
+ if (calculateTime.isSupported(ChronoField.YEAR)) {
+ return doShardingInYear(availableTargetNames, range, calculateTime);
+ }
+ if (calculateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ return doShardingInMonth(availableTargetNames, range, calculateTime);
+ }
}
- if (null == queryToLocalDate) {
+ if (!calculateTime.isSupported(ChronoField.EPOCH_DAY)) {
return doShardingInLocalTime(availableTargetNames, range, calculateTime);
}
return doShardingInLocalDateTime(availableTargetNames, range, calculateTime);
@@ -190,6 +203,48 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
}
return result;
}
+
+ private Collection<String> doShardingInYear(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
+ Set<String> result = new HashSet<>();
+ Year dateTimeUpperAsYear = dateTimeUpper.query(Year::from);
+ Year dateTimeLowerAsYear = dateTimeLower.query(Year::from);
+ Year calculateTimeAsView = calculateTime.query(Year::from);
+ while (!calculateTimeAsView.isAfter(dateTimeUpperAsYear)) {
+ if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsYear, dateTimeUpperAsYear)) {
+ result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
+ }
+ calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
+ }
+ return result;
+ }
+
+ private Collection<String> doShardingInMonth(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
+ Set<String> result = new HashSet<>();
+ Month dateTimeUpperAsMonth = dateTimeUpper.query(Month::from);
+ Month dateTimeLowerAsMonth = dateTimeLower.query(Month::from);
+ Month calculateTimeAsView = calculateTime.query(Month::from);
+ while (!(calculateTimeAsView.getValue() > dateTimeUpperAsMonth.getValue()) && (calculateTimeAsView.getValue() + stepAmount) <= Month.DECEMBER.getValue()) {
+ if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount)), range, dateTimeLowerAsMonth, dateTimeUpperAsMonth)) {
+ result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
+ }
+ calculateTimeAsView = calculateTimeAsView.plus(stepAmount);
+ }
+ return result;
+ }
+
+ private Collection<String> doShardingInYearMonth(final Collection<String> availableTargetNames, final Range<Comparable<?>> range, final TemporalAccessor calculateTime) {
+ Set<String> result = new HashSet<>();
+ YearMonth dateTimeUpperAsYearMonth = dateTimeUpper.query(YearMonth::from);
+ YearMonth dateTimeLowerAsYearMonth = dateTimeLower.query(YearMonth::from);
+ YearMonth calculateTimeAsView = calculateTime.query(YearMonth::from);
+ while (!calculateTimeAsView.isAfter(dateTimeUpperAsYearMonth)) {
+ if (hasIntersection(Range.closedOpen(calculateTimeAsView, calculateTimeAsView.plus(stepAmount, stepUnit)), range, dateTimeLowerAsYearMonth, dateTimeUpperAsYearMonth)) {
+ result.addAll(getMatchedTables(calculateTimeAsView, availableTargetNames));
+ }
+ calculateTimeAsView = calculateTimeAsView.plus(stepAmount, stepUnit);
+ }
+ return result;
+ }
private boolean hasIntersection(final Range<LocalDateTime> calculateRange, final Range<Comparable<?>> range, final LocalDateTime dateTimeLower, final LocalDateTime dateTimeUpper) {
LocalDateTime lower = range.hasLowerBound() ? parseLocalDateTime(range.lowerEndpoint()) : dateTimeLower;
@@ -217,6 +272,33 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
Range<LocalTime> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
}
+
+ private boolean hasIntersection(final Range<Year> calculateRange, final Range<Comparable<?>> range, final Year dateTimeLower, final Year dateTimeUpper) {
+ Year lower = range.hasLowerBound() ? parseYear(range.lowerEndpoint()) : dateTimeLower;
+ Year upper = range.hasUpperBound() ? parseYear(range.upperEndpoint()) : dateTimeUpper;
+ BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
+ BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
+ Range<Year> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
+ return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
+ }
+
+ private boolean hasIntersection(final Range<Month> calculateRange, final Range<Comparable<?>> range, final Month dateTimeLower, final Month dateTimeUpper) {
+ Month lower = range.hasLowerBound() ? parseMonth(range.lowerEndpoint()) : dateTimeLower;
+ Month upper = range.hasUpperBound() ? parseMonth(range.upperEndpoint()) : dateTimeUpper;
+ BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
+ BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
+ Range<Month> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
+ return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
+ }
+
+ private boolean hasIntersection(final Range<YearMonth> calculateRange, final Range<Comparable<?>> range, final YearMonth dateTimeLower, final YearMonth dateTimeUpper) {
+ YearMonth lower = range.hasLowerBound() ? parseYearMonth(range.lowerEndpoint()) : dateTimeLower;
+ YearMonth upper = range.hasUpperBound() ? parseYearMonth(range.upperEndpoint()) : dateTimeUpper;
+ BoundType lowerBoundType = range.hasLowerBound() ? range.lowerBoundType() : BoundType.CLOSED;
+ BoundType upperBoundType = range.hasUpperBound() ? range.upperBoundType() : BoundType.CLOSED;
+ Range<YearMonth> dateTimeRange = Range.range(lower, lowerBoundType, upper, upperBoundType);
+ return calculateRange.isConnected(dateTimeRange) && !calculateRange.intersection(dateTimeRange).isEmpty();
+ }
private LocalDateTime parseLocalDateTime(final Comparable<?> endpoint) {
return LocalDateTime.parse(getDateTimeText(endpoint).substring(0, dateTimePatternLength), dateTimeFormatter);
@@ -229,6 +311,18 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
private LocalTime parseLocalTime(final Comparable<?> endpoint) {
return LocalTime.parse(getDateTimeText(endpoint).substring(0, dateTimePatternLength), dateTimeFormatter);
}
+
+ private Year parseYear(final Comparable<?> endpoint) {
+ return Year.parse(getDateTimeText(endpoint).substring(0, dateTimePatternLength), dateTimeFormatter);
+ }
+
+ private Month parseMonth(final Comparable<?> endpoint) {
+ return (Month) endpoint;
+ }
+
+ private YearMonth parseYearMonth(final Comparable<?> endpoint) {
+ return YearMonth.parse(getDateTimeText(endpoint).substring(0, dateTimePatternLength), dateTimeFormatter);
+ }
private String getDateTimeText(final Comparable<?> endpoint) {
if (endpoint instanceof Instant) {
@@ -244,15 +338,27 @@ public final class IntervalShardingAlgorithm implements StandardShardingAlgorith
}
private Collection<String> getMatchedTables(final TemporalAccessor dateTime, final Collection<String> availableTargetNames) {
- LocalDate localDate = dateTime.query(TemporalQueries.localDate());
- LocalTime localTime = dateTime.query(TemporalQueries.localTime());
String tableSuffix;
- if (null == localTime) {
- tableSuffix = localDate.format(tableSuffixPattern);
- return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ if (!dateTime.isSupported(ChronoField.NANO_OF_DAY)) {
+ if (dateTime.isSupported(ChronoField.EPOCH_DAY)) {
+ tableSuffix = tableSuffixPattern.format(dateTime.query(TemporalQueries.localDate()));
+ return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ }
+ if (dateTime.isSupported(ChronoField.YEAR) && dateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ tableSuffix = tableSuffixPattern.format(dateTime.query(YearMonth::from));
+ return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ }
+ if (dateTime.isSupported(ChronoField.YEAR)) {
+ tableSuffix = tableSuffixPattern.format(dateTime.query(Year::from));
+ return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ }
+ if (dateTime.isSupported(ChronoField.MONTH_OF_YEAR)) {
+ tableSuffix = tableSuffixPattern.format(dateTime.query(Month::from));
+ return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
+ }
}
- if (null == localDate) {
- tableSuffix = localTime.format(tableSuffixPattern);
+ if (!dateTime.isSupported(ChronoField.EPOCH_DAY)) {
+ tableSuffix = dateTime.query(TemporalQueries.localTime()).format(tableSuffixPattern);
return availableTargetNames.parallelStream().filter(each -> each.endsWith(tableSuffix)).collect(Collectors.toSet());
}
tableSuffix = LocalDateTime.from(dateTime).format(tableSuffixPattern);
diff --git a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
index 5c11b55ec0f..5fb64997b19 100644
--- a/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
+++ b/shardingsphere-features/shardingsphere-sharding/shardingsphere-sharding-core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
@@ -33,8 +33,11 @@ import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+import java.time.Month;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@@ -60,6 +63,12 @@ public final class IntervalShardingAlgorithmTest {
private final Collection<String> availableTablesForJDBCTimeDataSources = new LinkedList<>();
+ private final Collection<String> availableTablesForYearDataSources = new LinkedList<>();
+
+ private final Collection<String> availableTablesForYearMonthDataSources = new LinkedList<>();
+
+ private final Collection<String> availableTablesForMonthInJSR310DataSources = new LinkedList<>();
+
private final Collection<String> availableTablesForDayWithMillisecondDataSources = new LinkedList<>();
private IntervalShardingAlgorithm shardingAlgorithmByQuarter;
@@ -74,6 +83,12 @@ public final class IntervalShardingAlgorithmTest {
private IntervalShardingAlgorithm shardingAlgorithmByDayWithMillisecond;
+ private IntervalShardingAlgorithm shardingAlgorithmByYear;
+
+ private IntervalShardingAlgorithm shardingAlgorithmByYearMonth;
+
+ private IntervalShardingAlgorithm shardingAlgorithmByMonthInJSR310;
+
@Before
public void setup() {
initShardStrategyByMonth();
@@ -82,6 +97,9 @@ public final class IntervalShardingAlgorithmTest {
initShardStrategyByDayWithMillisecond();
initShardingStrategyByJDBCDate();
initShardingStrategyByJDBCTime();
+ initShardingStrategyByYear();
+ initShardingStrategyByYearMonth();
+ initShardingStrategyByMonthInJSR310();
}
private void initShardStrategyByQuarter() {
@@ -207,6 +225,68 @@ public final class IntervalShardingAlgorithmTest {
result.setProperty("datetime-interval-unit", "Hours");
return result;
}
+
+ private void initShardingStrategyByYear() {
+ int stepAmount = 2;
+ shardingAlgorithmByYear = (IntervalShardingAlgorithm) ShardingAlgorithmFactory.newInstance(
+ new ShardingSphereAlgorithmConfiguration("INTERVAL", createYearProperties(stepAmount)));
+ for (int i = 2000; i < 2023; i++) {
+ availableTablesForYearDataSources.add(String.format("t_order_%04d", i));
+ }
+ }
+
+ private Properties createYearProperties(final int stepAmount) {
+ Properties result = new Properties();
+ result.setProperty("datetime-pattern", "yyyy");
+ result.setProperty("datetime-lower", "2000");
+ result.setProperty("datetime-upper", "2022");
+ result.setProperty("sharding-suffix-pattern", "yyyy");
+ result.setProperty("datetime-interval-amount", Integer.toString(stepAmount));
+ result.setProperty("datetime-interval-unit", "Years");
+ return result;
+ }
+
+ private void initShardingStrategyByYearMonth() {
+ int stepAmount = 2;
+ shardingAlgorithmByYearMonth = (IntervalShardingAlgorithm) ShardingAlgorithmFactory.newInstance(
+ new ShardingSphereAlgorithmConfiguration("INTERVAL", createYearMonthProperties(stepAmount)));
+ for (int i = 2016; i <= 2021; i++) {
+ for (int j = 1; j <= 12; j++) {
+ availableTablesForYearMonthDataSources.add(String.format("t_order_%04d%02d", i, j));
+ }
+ }
+ }
+
+ private Properties createYearMonthProperties(final int stepAmount) {
+ Properties result = new Properties();
+ result.setProperty("datetime-pattern", "yyyy-MM");
+ result.setProperty("datetime-lower", "2016-01");
+ result.setProperty("datetime-upper", "2021-12");
+ result.setProperty("sharding-suffix-pattern", "yyyyMM");
+ result.setProperty("datetime-interval-amount", Integer.toString(stepAmount));
+ result.setProperty("datetime-interval-unit", "Years");
+ return result;
+ }
+
+ private void initShardingStrategyByMonthInJSR310() {
+ int stepAmount = 2;
+ shardingAlgorithmByMonthInJSR310 = (IntervalShardingAlgorithm) ShardingAlgorithmFactory.newInstance(
+ new ShardingSphereAlgorithmConfiguration("INTERVAL", createMonthInJSR310Properties(stepAmount)));
+ for (int i = 2; i < 13; i++) {
+ availableTablesForMonthInJSR310DataSources.add(String.format("t_order_%02d", i));
+ }
+ }
+
+ private Properties createMonthInJSR310Properties(final int stepAmount) {
+ Properties result = new Properties();
+ result.setProperty("datetime-pattern", "MM");
+ result.setProperty("datetime-lower", "02");
+ result.setProperty("datetime-upper", "12");
+ result.setProperty("sharding-suffix-pattern", "MM");
+ result.setProperty("datetime-interval-amount", Integer.toString(stepAmount));
+ result.setProperty("datetime-interval-unit", "Months");
+ return result;
+ }
@Test
public void assertPreciseDoShardingByQuarter() {
@@ -352,4 +432,17 @@ public final class IntervalShardingAlgorithmTest {
OffsetTime.of(12, 25, 27, 0, OffsetDateTime.now().getOffset()))));
assertThat(actualAsOffsetTime.size(), is(6));
}
+
+ @Test
+ public void assertIntegerInJDBCType() {
+ Collection<String> actualAsYear = shardingAlgorithmByYear.doSharding(availableTablesForYearDataSources,
+ new RangeShardingValue<>("t_order", "create_time", DATA_NODE_INFO, Range.closed(Year.of(2001), Year.of(2013))));
+ assertThat(actualAsYear.size(), is(7));
+ Collection<String> actualAsYearMonth = shardingAlgorithmByYearMonth.doSharding(availableTablesForYearMonthDataSources,
+ new RangeShardingValue<>("t_order", "create_time", DATA_NODE_INFO, Range.closed(YearMonth.of(2016, 1), YearMonth.of(2020, 1))));
+ assertThat(actualAsYearMonth.size(), is(3));
+ Collection<String> actualAsMonth = shardingAlgorithmByMonthInJSR310.doSharding(availableTablesForMonthInJSR310DataSources,
+ new RangeShardingValue<>("t_order", "create_time", DATA_NODE_INFO, Range.closed(Month.of(4), Month.of(10))));
+ assertThat(actualAsMonth.size(), is(4));
+ }
}