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 <[email protected]>
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));
+ }
}