Skip to content

Commit

Permalink
Add list and rebalance CLI actions; remove non-masters from DSNs
Browse files Browse the repository at this point in the history
  • Loading branch information
dimikot committed Sep 17, 2024
1 parent 2fa817e commit 37a3e3b
Show file tree
Hide file tree
Showing 31 changed files with 1,086 additions and 196 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,21 @@ Each microshard can either be "active" or "inactive".
The library exposes command-line tool `pg-microsharding`. Some (non-exhaustive)
list of commands:

- `pg-microsharding list`
- `pg-microsharding allocate --shards=N-M ...`
- `pg-microsharding move --shard=N --from=DSN --to=DSN ...`
- `pg-microsharding cleanup --dsn=DSN`
- `pg-microsharding rebalance ...`
- `pg-microsharding cleanup`
- ...
- run the tool to see other commands and options.
- run the tool to see other commands, options and environment variables.

It also provides low-level stored functions API:
Exposes a performant stored functions API for microshards discovery (it's
supposed to be called from all nodes of the cluster from time to time):

- `microsharding_list_active_shards()`: returns the list of "active" shards

It also provides system administration stored functions API:

- `microsharding_do_on_each()`: a helper function to run an SQL query on all shards
- `microsharding_debug_views_create()`: creates "debug views" for tables in all
microshards that union SELECTs from the same-named tables in all shards (not
Expand Down
12 changes: 9 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@ Each microshard can either be "active" or "inactive".
The library exposes command-line tool `pg-microsharding`. Some (non-exhaustive)
list of commands:

- `pg-microsharding list`
- `pg-microsharding allocate --shards=N-M ...`
- `pg-microsharding move --shard=N --from=DSN --to=DSN ...`
- `pg-microsharding cleanup --dsn=DSN`
- `pg-microsharding rebalance ...`
- `pg-microsharding cleanup`
- ...
- run the tool to see other commands and options.
- run the tool to see other commands, options and environment variables.

It also provides low-level stored functions API:
Exposes a performant stored functions API for microshards discovery (it's
supposed to be called from all nodes of the cluster from time to time):

- `microsharding_list_active_shards()`: returns the list of "active" shards

It also provides system administration stored functions API:

- `microsharding_do_on_each()`: a helper function to run an SQL query on all shards
- `microsharding_debug_views_create()`: creates "debug views" for tables in all
microshards that union SELECTs from the same-named tables in all shards (not
Expand Down
13 changes: 13 additions & 0 deletions docs/interfaces/Shard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[@clickup/pg-microsharding](../README.md) / [Exports](../modules.md) / Shard

# Interface: Shard

## Properties

### weight

**weight**: `number`

#### Defined in

[src/api/rebalance.ts:15](https://github.com/clickup/pg-microsharding/blob/master/src/api/rebalance.ts#L15)
171 changes: 166 additions & 5 deletions docs/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,145 @@

# @clickup/pg-microsharding

## Interfaces

- [Shard](interfaces/Shard.md)

## Functions

### actionAllocate

**actionAllocate**(`args`): `Promise`\<`boolean`\>

Ensures that some shards exist.

#### Parameters

| Name | Type |
| :------ | :------ |
| `args` | `ParsedArgs` |

#### Returns

`Promise`\<`boolean`\>

#### Defined in

src/actions/actionAllocate.ts:9

___

### actionCleanup

**actionCleanup**(`args`): `Promise`\<`boolean`\>

Removes previously moved schema originals from the source database.

#### Parameters

| Name | Type |
| :------ | :------ |
| `args` | `ParsedArgs` |

#### Returns

`Promise`\<`boolean`\>

#### Defined in

src/actions/actionCleanup.ts:11

___

### actionList

**actionList**(`args`): `Promise`\<`boolean`\>

Shows the list of microshards and their weights.

#### Parameters

| Name | Type |
| :------ | :------ |
| `args` | `ParsedArgs` |

#### Returns

`Promise`\<`boolean`\>

#### Defined in

src/actions/actionList.ts:16

___

### calcIslandWeights

**calcIslandWeights**(`«destructured»`): `Promise`\<\{ `islandNosToDsn`: `Map`\<`number`, `string`\> ; `islands`: `Map`\<`number`, `NonNullable`\<`Awaited`\<`ReturnType`\<typeof [`weights`](modules.md#weights)\>\>\>\> }\>

#### Parameters

| Name | Type |
| :------ | :------ |
| `«destructured»` | `Object` |
| › `dsns` | `string`[] |
| › `weightSql` | `undefined` \| `string` |
| › `includeIsolatedShard0` | `boolean` |

#### Returns

`Promise`\<\{ `islandNosToDsn`: `Map`\<`number`, `string`\> ; `islands`: `Map`\<`number`, `NonNullable`\<`Awaited`\<`ReturnType`\<typeof [`weights`](modules.md#weights)\>\>\>\> }\>

#### Defined in

src/actions/actionList.ts:92

___

### actionMove

**actionMove**(`args`): `Promise`\<`boolean`\>

Moves a shard from one database to another with no downtime.

#### Parameters

| Name | Type |
| :------ | :------ |
| `args` | `ParsedArgs` |

#### Returns

`Promise`\<`boolean`\>

#### Defined in

src/actions/actionMove.ts:11

___

### actionRebalance

**actionRebalance**(`args`): `Promise`\<`boolean`\>

Runs a series of shard modes, concurrently, using TMUX if available.

#### Parameters

| Name | Type |
| :------ | :------ |
| `args` | `ParsedArgs` |

#### Returns

`Promise`\<`boolean`\>

#### Defined in

src/actions/actionRebalance.ts:27

___

### allocate

**allocate**(`«destructured»`): `Promise`\<`void`\>
Expand All @@ -28,7 +165,7 @@ script (presumably DB migration), and then optionally activates the shards.

#### Defined in

src/api/allocate.ts:10
[src/api/allocate.ts:10](https://github.com/clickup/pg-microsharding/blob/master/src/api/allocate.ts#L10)

___

Expand Down Expand Up @@ -131,7 +268,7 @@ doesn't matter much though, because shards sizes are more or less equal.

| Name | Type |
| :------ | :------ |
| `TShard` | extends `Shard` |
| `TShard` | extends [`Shard`](interfaces/Shard.md) |

#### Parameters

Expand All @@ -151,12 +288,36 @@ doesn't matter much though, because shards sizes are more or less equal.

___

### weights

**weights**(`«destructured»`): `Promise`\<\{ `weight`: `number` ; `unit`: `string` \| `undefined` ; `schema`: `string` ; `no`: `number` }[] \| ``null``\>

Similar tp listActiveSchemas(), but also returns the weight of each
microshard and its number.

#### Parameters

| Name | Type |
| :------ | :------ |
| `«destructured»` | `Object` |
| › `dsn` | `string` |
| › `weightSql` | `undefined` \| `string` |
| › `includeIsolatedShard0` | `boolean` |

#### Returns

`Promise`\<\{ `weight`: `number` ; `unit`: `string` \| `undefined` ; `schema`: `string` ; `no`: `number` }[] \| ``null``\>

#### Defined in

src/api/weights.ts:10

___

### main

**main**(`argv`): `Promise`\<`boolean`\>

CLI script entry point.

#### Parameters

| Name | Type |
Expand All @@ -169,4 +330,4 @@ CLI script entry point.

#### Defined in

[src/cli.ts:39](https://github.com/clickup/pg-microsharding/blob/master/src/cli.ts#L39)
[src/cli.ts:67](https://github.com/clickup/pg-microsharding/blob/master/src/cli.ts#L67)
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@clickup/pg-microsharding",
"description": "Microshards support for PostgreSQL",
"version": "2.12.1",
"version": "2.12.2",
"license": "MIT",
"keywords": [
"postgresql",
Expand Down Expand Up @@ -35,7 +35,8 @@
"minimist": "^1.2.5",
"pg": "^8.7.1",
"prompts": "^2.4.2",
"sprintf-js": "^1.1.2"
"sprintf-js": "^1.1.2",
"tmp": "^0.2.1"
},
"devDependencies": {
"@types/jest": "^29.5.5",
Expand All @@ -45,6 +46,7 @@
"@types/pg": "^8.6.1",
"@types/prompts": "^2.4.0",
"@types/sprintf-js": "^1.1.2",
"@types/tmp": "^0.2.6",
"@typescript-eslint/eslint-plugin": "^5.59.6",
"@typescript-eslint/parser": "^5.59.6",
"eslint-import-resolver-typescript": "^3.5.5",
Expand All @@ -60,6 +62,7 @@
"eslint": "^8.40.0",
"jest": "^29.7.0",
"prettier": "3.2.1",
"table": "^6.8.0",
"ts-jest": "^29.1.1",
"typedoc-plugin-markdown": "^3.16.0",
"typedoc-plugin-merge-modules": "^5.1.0",
Expand Down
39 changes: 39 additions & 0 deletions src/actions/actionAllocate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { ParsedArgs } from "minimist";
import { allocate } from "../api/allocate";
import { isTrueValue } from "../internal/isTrueValue";
import { normalizeDsns } from "../internal/normalizeDsns";

/**
* Ensures that some shards exist.
*/
export async function actionAllocate(args: ParsedArgs): Promise<boolean> {
const dsns = await normalizeDsns(args["dsns"] || args["dsn"]);
if (dsns.length === 0) {
throw "Please provide --dsn, DB DSN to allocate microshard(s) at";
}

let from: number;
let to: number;
if ((args["shard"] || args["shards"])?.match(/^(\d+)(?:-(\d+))?$/)) {
from = parseInt(RegExp.$1, 10);
to = parseInt(RegExp.$2 || String(from), 10);
} else {
throw "Please provide --shard=N or --shards=N-M, starting and ending shard numbers";
}

let migrateCmd: string;
if (args["migrate-cmd"]) {
migrateCmd = args["migrate-cmd"];
} else {
throw "Please provide --migrate-cmd, shell command to run migrations in between shards creation and activation";
}

const activate = isTrueValue(args["activate"] ?? "");
if (activate === undefined) {
throw "Please provide --activate=yes or --activate=no";
}

await allocate({ dsn: dsns[0], from, to, migrateCmd, activate });

return true;
}
37 changes: 37 additions & 0 deletions src/actions/actionCleanup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { ParsedArgs } from "minimist";
import prompts from "prompts";
import { cleanup } from "../api/cleanup";
import { print } from "../internal/logging";
import { dsnShort } from "../internal/names";
import { normalizeDsns } from "../internal/normalizeDsns";

/**
* Removes previously moved schema originals from the source database.
*/
export async function actionCleanup(args: ParsedArgs): Promise<boolean> {
const dsns = await normalizeDsns(args["dsns"] || args["dsn"]);
if (dsns.length === 0) {
throw "Please provide --dsn or --dsns, DB DSNs to remove old schemas from";
}

for (const dsn of dsns) {
print(`Cleaning up ${dsnShort(dsn)}...`);
await cleanup({
dsn,
noOldShards: async (oldSchemaNameRe) =>
print(`No old shard schemas matching regexp ${oldSchemaNameRe}`),
confirm: async (schemas) => {
const response = await prompts({
type: "text",
name: "value",
message: `Delete redundant schemas ${schemas.join(", ")} (y/n)?`,
validate: (value: string) =>
value !== "y" && value !== "n" ? 'Enter "y" or "n".' : true,
});
return response.value === "y";
},
});
}

return true;
}
Loading

0 comments on commit 37a3e3b

Please sign in to comment.