Skip to content
Open
88 changes: 88 additions & 0 deletions MAINTAINERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# PikiwiDB Maintainers

This document lists the maintainers, committers, and notable contributors of the PikiwiDB project.

## Roles

| Role | Description |
|------|-------------|
| **Maintainer** | Has write access to the repository, reviews and merges PRs, makes release decisions, and drives project direction. |
| **Committer** | Active contributor with elevated trust; reviews PRs and contributes significant features or fixes over multiple releases. |
| **Notable Contributor** | Has made meaningful one-off or focused contributions (features, bug fixes, tests, docs, tooling). |

## Maintainers

| GitHub ID | Name | Organization | Email |
|-----------|------|--------------|-------|
| [@wangshao1](https://github.com/wangshao1) | wangshao1 | — | — |
| [@Mixficsol](https://github.com/Mixficsol) | Mixficsol | — | — |
| [@chejinge](https://github.com/chejinge) | chejinge | 360 | [email protected] |

## Committers

Committers have a sustained history of high-quality contributions across multiple releases.

| GitHub ID | Name |
|-----------|------|
| [@wangshao1](https://github.com/wangshao1) | wangshao1 |
| [@chejinge](https://github.com/chejinge) | chejinge |
| [@Mixficsol](https://github.com/Mixficsol) | Mixficsol |
| [@chenbt-hz](https://github.com/chenbt-hz) | chenbt |
| [@guangkun123](https://github.com/guangkun123) | guangkun |
| [@wanghenshui](https://github.com/wanghenshui) | wanghenshui |
| [@machily](https://github.com/machily) | machily |
| [@QX](https://github.com/QX) | QX |

## Notable Contributors

The following contributors have made meaningful contributions to specific features, bug fixes, tests, or tooling.

| GitHub ID | Name |
|-----------|------|
| [@vacheli](https://github.com/vacheli) | vacheli |
| [@bigdaronlee163](https://github.com/bigdaronlee163) | bigdaronlee163 |
| [@longfar-ncy](https://github.com/longfar-ncy) | longfar-ncy |
| [@gukj-spel](https://github.com/gukj-spel) | gukj-spel |
| [@MalikHou](https://github.com/MalikHou) | MalikHou |
| [@hahahashen](https://github.com/hahahashen) | hahahashen |
| [@KKorpse](https://github.com/KKorpse) | KKorpse |
| [@sjcsjc123](https://github.com/sjcsjc123) | sjcsjc123 |
| [@JasirVoriya](https://github.com/JasirVoriya) | JasirVoriya |
| [@HappyUncle](https://github.com/HappyUncle) | HappyUncle |
| [@Y-Rookie](https://github.com/Y-Rookie) | Y-Rookie |
| [@panlei-coder](https://github.com/panlei-coder) | panlei-coder |
| [@tedli](https://github.com/tedli) | tedli |
| [@chienguo](https://github.com/chienguo) | chienguo |
| [@Polaris3003](https://github.com/Polaris3003) | Polaris3003 |
| [@callme-taota](https://github.com/callme-taota) | callme-taota |
| [@jettcc](https://github.com/jettcc) | jettcc |
| [@ForestLH](https://github.com/ForestLH) | ForestLH |
| [@tsinow](https://github.com/tsinow) | tsinow |
| [@saz97](https://github.com/saz97) | saz97 |
| [@u6th9d](https://github.com/u6th9d) | u6th9d |
| [@Tianpingan](https://github.com/Tianpingan) | Tianpingan |
| [@machinly](https://github.com/machinly) | machinly |
| [@hero-heng](https://github.com/hero-heng) | hero-heng |
| [@baixin01](https://github.com/baixin01) | baixin01 |
| [@xiezheng-XD](https://github.com/xiezheng-XD) | xiezheng-XD |
| [@A2ureStone](https://github.com/A2ureStone) | A2ureStone |
| [@klboke](https://github.com/klboke) | klboke |
| [@007gzs](https://github.com/007gzs) | 007gzs |

## Emeritus Maintainers

Individuals who have previously served as maintainers and have since stepped back.
We thank them for their valuable contributions.

<!-- Add emeritus maintainers here when applicable -->

## How to Become a Committer or Maintainer

- **Committer**: Submit high-quality contributions over time, actively participate in code reviews, and be nominated by an existing Maintainer.
- **Maintainer**: Demonstrate deep understanding of the codebase, a sustained track record as a Committer, and be approved by a majority of existing Maintainers.

Nominations are discussed in the project's community channels. Please reach out to the project team at [[email protected]](mailto:[email protected]) if you are interested.

## Contact

For governance-related inquiries, please open an issue or contact [[email protected]](mailto:[email protected]).
266 changes: 266 additions & 0 deletions codis/doc/redis_change_en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
### Redis Modifications (Additional Commands)
--------------------------------

##### SLOTSINFO [start] [count]

+ Description: Returns slot metadata in Redis, including slot ID and key count for each slot.

+ Parameters: Defaults to querying `[0, MAX_SLOT_NUM)`.

- `start`: starting slot ID (default `0`)
- `count`: size of the range to query, i.e. `[start, start + count)` (default `MAX_SLOT_NUM`)

+ Return: an array of `slotinfo` items, where each `slotinfo` is `[slotnum, slotsize]`.

response := []slotinfo{slot1, slot2, slot3, ...}
slotinfo := []int{slotnum, slotsize}

where:
INT slotnum : slot ID
INT slotsize : number of keys in the slot

+ Example:

localhost:6379> slotsinfo 0 128
1) 1) (integer) 23
2) (integer) 2
2) 1) (integer) 29
2) (integer) 1

##### SLOTSSCAN slotnum cursor [COUNT count]

+ Description: Scans keys in a specific slot.

+ Parameters: Similar to `SCAN`.

- `slotnum`: slot ID to scan, in `[0, MAX_SLOT_NUM)`
- `cursor`: same semantics as `SCAN`
- `[COUNT count]`: same semantics as `SCAN`
- `MATCH` is currently not supported

+ Return: same format as `SCAN`.

- Returns updated cursor and a key list.

+ Example:

localhost:6379> slotsscan 579 0 COUNT 10
1) "10752"
2) 1) "{a}7836"
2) "{a}2167"
3) "{a}5332"
4) "{a}6292"
5) "{a}600"
6) "{a}6094"
7) "{a}7754"
8) "{a}4929"
9) "{a}9211"
10) "{a}6596"

##### SLOTSDEL slot1 [slot2 …]

+ Description: Deletes all key-value pairs in one or more slots.

+ Parameters: Accepts at least one slot ID.

+ Return: Same structure as `slotsinfo`; `slotsize` means remaining keys after deletion (usually `0`).

+ Example:

localhost:6379> slotsdel 1013 990
1) 1) (integer) 1013
2) (integer) 0
2) 1) (integer) 990
2) (integer) 0

#### Data Migration
---------------

**The following 4 commands are a migration family:**

+ `SLOTSMGRTSLOT` - *O(1)*

Randomly migrates one key-value pair from a slot to the target node.

+ `SLOTSMGRTONE` - *O(1)*

Migrates the specified key-value pair to the target node.

+ `SLOTSMGRTTAGSLOT` - *O(log(n))*

Randomly picks one key from a slot and migrates all key-value pairs with the same tag.

+ `SLOTSMGRTTAGONE` - *O(log(n))*

Migrates all key-value pairs that share the same tag as the specified key.

##### SLOTSMGRTSLOT host port timeout slot

+ Description: Randomly migrates one key-value pair from the specified slot to the target node (synchronous I/O).

- Returns `0` if the slot is empty or the selected key expired.
- If the slot still has keys, one key is selected and migrated.
- Also returns the remaining key count in the slot.
- Migration triggers `slotsrestore` on the destination and **overwrites existing values**.

+ Parameters:

- `host:port`: destination node

Redis caches the connection to `host:port` for 30s, and closes it on timeout/error.

- `timeout`: timeout in milliseconds

The operation includes three synchronous stages:

1. connect (may use cached connection)
2. send key-value data
3. receive response from destination

Each stage is bounded by `timeout`.

- `slot`: slot ID to migrate from

+ Return: integer array

response := []int{succ,size}

where:
INT succ : migration result
0 -> slot is empty (migrated keys = 0)
1 -> one key migrated and removed locally (migrated keys = 1)
INT size : remaining key count in the slot

+ Example:

localhost:6379> set a 100 # set <a, 100>
OK
localhost:6379> slotsinfo # slot size = 1
1) 1) (integer) 579
2) (integer) 1
localhost:6379> slotsmgrt 127.0.0.1 6380 100 579
(integer) 1 # migrated successfully
localhost:6379> slotsinfo
(empty list or set)
localhost:6379> slotsmgrt 127.0.0.1 6380 100 579 1
(integer) 0 # migrated count = 0; slot already empty

##### SLOTSMGRTONE host port timeout key

+ Description: Migrates the specified key to the destination. Semantics are similar to `slotsmgrtslot`.

+ Parameters: see `slotsmgrtslot`.

+ Return: integer

response := int(succ)

where:
INT succ : same semantics as `slotsmgrtslot`

+ Example:

localhost:6379> set a 100 # set <a, 100>
OK
localhost:6379> slotsinfo
1) 1) (integer) 579
2) (integer) 1
localhost:6379> slotsmgrtone 127.0.0.1 6380 100 a
(integer) 1 # migration succeeded
localhost:6379> slotsmgrtone 127.0.0.1 6380 100 a
(integer) 0 # skipped: key does not exist locally

##### SLOTSMGRTTAGONE host port timeout key

+ Description: Migrates all keys that share the same tag as `key`.

- If `key` has no valid tag, it degrades to `slotsmgrtone`, with complexity ***O(1)***.
- If `key` has a valid tag, it hashes the tag and finds all matching keys in skiplist, then migrates them atomically, with complexity ***O(log(n))***.
- Note: In the modified Redis, tagged keys are organized in a skiplist by tag hash. Migration by tag may include more keys with the same hash. This design reduces string comparisons during tag migration and improves performance.

+ Parameters: see `slotsmgrtone`.

+ Return: integer

response := int(succ)

where:
INT succ : number of keys migrated successfully

+ Example:

localhost:6379> set a{tag} 100 # set <a{tag}, 100>
OK
localhost:6379> set b{tag} 100 # set <b{tag}, 100>
OK
localhost:6379> slotsmgrttag 127.0.0.1 6380 1000 {tag}
(integer) 2
localhost:6379> scan 0 # migrated, no local data
1) "0"
2) (empty list or set)
localhost:6380> scan 0 # data appears on destination
1) "0"
2) 1) "a{tag}"
2) "b{tag}"

##### SLOTSMGRTTAGSLOT host port timeout slot

+ Description: Tag-based migration counterpart of `slotsmgrtslot`.

- Refer to `slotsmgrtslot` and `slotsmgrttagone` for behavior details.

##### SLOTSRESTORE key1 ttl1 val1 [key2 ttl2 val2 …]

+ Description: Extension of Redis 2.8 `restore` command.

- Supports restoring multiple key-value pairs at once.
- The operation is atomic.

+ Note: Unlike `restore`, `slotsrestore` only supports `replace`, i.e. it always **overwrites old values**. If old values already exist, it is usually a bug in redis-slots or proxy implementation, and Redis logs a conflict record.

#### Debug Commands
---------------

##### SLOTSHASHKEY key1 [key2 …]

+ Description: Computes and returns slot IDs of input keys.

+ Parameters: one or more keys.

+ Return: array

response := []int{slot1, slot2...}

where:
INT slot : slot ID of the key, i.e. hash32(key) % NUM_OF_SLOTS

+ Example:

localhost:6379> slotshashkey a b c # compute slot IDs of <a,b,c>
1) (integer) 579
2) (integer) 1017
3) (integer) 879

##### SLOTSCHECK

+ Description: Performs slot consistency checking in Redis. It verifies:

- Every key recorded in a slot exists in DB.
- Every DB key can be found in its corresponding slot.

+ Parameters: no arguments.

+ Return: string `OK` on success (or `ERR` with related key when check fails).

+ Example:

localhost:6379> set a 100 # set <a, 100>
OK
localhost:6379> slotscheck
OK # check passed
localhost:6379> slotscheck
OK # check passed, took 1.07s
(1.07s)

+ **Note**: This operation is relatively slow and should be used only as a development/debugging tool, not in production.
Loading
Loading