cosid-sharding · git:20261027.4a2e10f · 2026-10-27 · sha256 144167c08e09e6be

cosid-sharding git:20261027.4a2e10fA

Immutable. This exact content never changes and is served at /api/v1/blob/144167c08e09e6be.

---
name: cosid-sharding
description: Design, implement, and validate database sharding with the cosid-sharding module (ModCycle, IntervalTimeline, CachedSharding, ShardingRange, StandardLocalDateTimeConvertor, SnowflakeLocalDateTimeConvertor on a Layout) or ShardingSphere's COSID_MOD, COSID_INTERVAL and COSID_INTERVAL_SNOWFLAKE algorithms. Use for modulo routing, date/time partitions, Snowflake timestamp routing, exact/IN/range behavior, effective nodes, suffix naming, or routing tests. Do not use for choosing an ID generator unless sharding is the primary concern.
---

# Design CosId Sharding

Treat the core Java sharding API and ShardingSphere configuration as separate integration surfaces. The algorithms
live in `me.ahoo.cosid:cosid-sharding` (package `me.ahoo.cosid.sharding`), released with CosId and depending on
`cosid-core` only (D7). In CosId 5 a range is a `ShardingRange` (Guava's `Range` is gone; the factory names are the
same), and the Snowflake convertor takes a `Layout`. Verify the target CosId and ShardingSphere versions before copying
property names.

## Workflow

1. Identify the sharding key type and every query operator that must route: exact, `IN`, and range.
2. Define physical nodes, naming, bounds, and future partition provisioning before selecting an algorithm.
3. Choose `ModCycle` for fixed-count numeric distribution or `IntervalTimeline` for time partitions.
4. Add Snowflake conversion only when the id `Layout` (epoch, unit, bits) is known.
5. Build a routing matrix that covers boundaries, out-of-range values, and full-range queries.

## Core Algorithms

| API | Use | Important behavior |
|---|---|---|
| `ModCycle<T extends Number>` | fixed number of numeric nodes | exact route is `floorMod(value, divisor)` → `{prefix}{index}`; a range spanning `divisor` values or unbounded above routes to every node |
| `IntervalTimeline` | bounded `LocalDateTime` partitions | exact values outside the effective interval throw `IllegalArgumentException`; a range not connected to it routes to no node |
| `StandardLocalDateTimeConvertor(zone, isSecondTs, formatter)` | column values to `LocalDateTime` | `LocalDateTime`, `ZonedDateTime`, `OffsetDateTime`, `Instant`, `LocalDate`, `Date`, `YearMonth`, `Year`, epoch `Long`, formatted `String` |
| `SnowflakeLocalDateTimeConvertor(layout, zone[, codec])` | Snowflake `Long` or text to its issue time | `layout.unpack`; text through the codec, base 62 / 11 digits / padded by default |
| `CachedSharding<T>` | reuse identical range results | bounded (10 000 ranges by default, emptied when full) |

### Modulo Example

```java
ModCycle<Long> sharding = new ModCycle<>(4, "t_order_");

String exact = sharding.sharding(42L); // t_order_2
Collection<String> range = sharding.sharding(ShardingRange.closed(1L, 10L));
```

A range spanning at least `divisor` consecutive values routes to every node. Include open and unbounded ranges in tests.

### Interval Example

```java
IntervalTimeline timeline = new IntervalTimeline(
    "t_order_",
    ShardingRange.closed(
        LocalDateTime.of(2026, 1, 1, 0, 0),
        LocalDateTime.of(2026, 12, 31, 23, 59, 59)
    ),
    IntervalStep.of(ChronoUnit.MONTHS),
    DateTimeFormatter.ofPattern("yyyyMM")
);

String exact = timeline.sharding(LocalDateTime.of(2026, 3, 15, 10, 30));
Collection<String> range = timeline.sharding(ShardingRange.closed(
    LocalDateTime.of(2026, 3, 1, 0, 0),
    LocalDateTime.of(2026, 4, 30, 23, 59, 59)
));
```

Supported `IntervalStep` units are years, months, days, hours, minutes, and seconds. Ensure the suffix format is unique for the selected step.

### Snowflake Conversion

```java
SnowflakeLocalDateTimeConvertor convertor =
    new SnowflakeLocalDateTimeConvertor(Layout.SNOWFLAKE_MS, ZoneId.of("Asia/Shanghai"));

LocalDateTime time = convertor.toLocalDateTime(runtime.generator("default").generate());
```

Pass the generator's real layout (`runtime.get(name, TimeBasedGenerator.class).layout()`). The convertor accepts `Long`
and text values only; text decodes through its `IdCodec`.

## ShardingSphere

ShardingSphere's `COSID_*` algorithms are maintained in ShardingSphere, not in `cosid-sharding`, and depend on the CosId version ShardingSphere bundles; their availability and properties vary by release. Inspect the target artifact or official source before emitting a type. When `COSID_MOD` is available, its divisor property is named `mod`, not `divisor`:

```yaml
rules:
  - !SHARDING
    tables:
      t_order:
        actualDataNodes: ds_0.t_order_$->{0..3}
        tableStrategy:
          standard:
            shardingColumn: order_id
            shardingAlgorithmName: t_order_mod
    shardingAlgorithms:
      t_order_mod:
        type: COSID_MOD
        props:
          mod: 4
          logic-name-prefix: t_order_
```

For ordinary time keys, configure an available `COSID_INTERVAL` implementation with `datetime-lower`, `datetime-upper`, `sharding-suffix-pattern`, `datetime-interval-unit`, and `datetime-interval-amount`.

Handle Snowflake interval routing by version:

- Prefer the core API shown above when application code owns routing; `SnowflakeLocalDateTimeConvertor(layout, zone)` follows the actual generator's `Layout`.
- In Apache ShardingSphere 5.4.0, `COSID_INTERVAL_SNOWFLAKE` reads only `epoch` and `zone-id` and hardcodes the default millisecond Snowflake layout. Use it only for that layout; `id-name` does not align a custom generator.
- For every other ShardingSphere release, verify that the CosId plugin and requested properties exist. Do not emit `COSID_INTERVAL_SNOWFLAKE` merely because an older document lists it.
- For a custom bit layout, use a version-verified integration that resolves the actual generator or a minimal `StandardShardingAlgorithm` that delegates to `SnowflakeLocalDateTimeConvertor` and `IntervalTimeline`.

Ensure `actualDataNodes` enumerates only valid physical suffixes; a daily numeric range such as `${20240101..20241231}` also generates impossible dates and must not be used.

## Validation Matrix

Test at least:

- first and last exact key for every boundary node;
- one `IN` set spanning multiple nodes;
- closed, open, unbounded, empty, and out-of-domain ranges;
- negative values for `ModCycle` (floor-mod);
- an interval transition such as month-end or year-end;
- Snowflake values generated with the actual epoch, unit, and bit layout;
- equality between algorithm effective nodes and provisioned physical nodes.

## Response Contract

Return the chosen algorithm, physical naming model, minimal Java or version-matched ShardingSphere configuration, and the routing matrix. Call out any partition provisioning risk explicitly.