@clickup/pg-microsharding
Version:
Microshards support for PostgreSQL
208 lines • 10.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.actionList = actionList;
exports.calcIslandWeights = calcIslandWeights;
const chalk_1 = __importDefault(require("chalk"));
const chunk_1 = __importDefault(require("lodash/chunk"));
const compact_1 = __importDefault(require("lodash/compact"));
const first_1 = __importDefault(require("lodash/first"));
const flatten_1 = __importDefault(require("lodash/flatten"));
const mapValues_1 = __importDefault(require("lodash/mapValues"));
const max_1 = __importDefault(require("lodash/max"));
const range_1 = __importDefault(require("lodash/range"));
const round_1 = __importDefault(require("lodash/round"));
const sum_1 = __importDefault(require("lodash/sum"));
const sumBy_1 = __importDefault(require("lodash/sumBy"));
const table_1 = require("table");
const weights_1 = require("../api/weights");
const chunkIntoN_1 = require("../internal/chunkIntoN");
const getSchemaWeights_1 = require("../internal/getSchemaWeights");
const indent_1 = require("../internal/indent");
const logging_1 = require("../internal/logging");
const names_1 = require("../internal/names");
const normalizeDsns_1 = require("../internal/normalizeDsns");
const pluralize_1 = require("../internal/pluralize");
const promiseAllMap_1 = require("../internal/promiseAllMap");
const DEBUG_RENDER_MUL = parseInt((_a = process.env["DEBUG_RENDER_MUL"]) !== null && _a !== void 0 ? _a : "0") || 0;
/**
* Shows the list of microshards and their weights.
*/
async function actionList(args) {
var _a, _b;
const weightSql = args["weight-sql"] || undefined;
const verbose = !!args["verbose"];
const json = !!args["json"];
const dsns = await (0, normalizeDsns_1.normalizeDsns)(args["dsns"] || args["dsn"]);
if (dsns.length === 0) {
throw "Please provide --dsn or --dsns, DB DSNs to list the microshards on";
}
const { islandNosToDsn, islands } = await calcIslandWeights({
dsns,
weightSql,
verbose,
});
if (DEBUG_RENDER_MUL > 0) {
[...islands.values()].forEach((shards) => shards.push(...(0, flatten_1.default)((0, range_1.default)(DEBUG_RENDER_MUL - 1).map(() => shards))));
}
const grandTotalWeightColName = (_a = (0, first_1.default)((0, flatten_1.default)([...islands.values()]).map((s) => s.weightColName))) !== null && _a !== void 0 ? _a : getSchemaWeights_1.WEIGHT_COL_NAME_DEFAULT;
const grandTotalWeight = (0, round_1.default)((0, sum_1.default)((0, flatten_1.default)([...islands.values()]).map((s) => s.weight)), 2);
const grandTotalUnit = (0, first_1.default)((0, compact_1.default)((0, flatten_1.default)([...islands.values()]).map((s) => s.unit)));
const grandTotalShards = (0, sum_1.default)([...islands.values()].map((s) => s.length));
const firstShard = (0, first_1.default)((0, first_1.default)([...islands.values()].filter((s) => s.length > 0)));
const header = ["Microshard"].concat(firstShard
? [
firstShard.weightColName,
`${firstShard.weightColName} %`,
...Object.keys(firstShard.other),
]
: [getSchemaWeights_1.WEIGHT_COL_NAME_DEFAULT, `${getSchemaWeights_1.WEIGHT_COL_NAME_DEFAULT} %`]);
// Width in characters of the longest rendered table row.
const tableWidth = 2 + // indent
header.length * 3 + // left borders and paddings around each cell
1 + // last border
((_b = (0, max_1.default)(
// content of the longest row
(0, flatten_1.default)([...islands.values()]).map(({ weight, appliedFactor, unit, otherNormalized, no }) =>
// Microshard
Math.max(header[0].length, no.toString().length) +
// Weight or Size or ...
Math.max(header[2].length, (0, round_1.default)(weight / appliedFactor, 5).toString().length +
(unit ? unit.length + 1 : 0) +
(appliedFactor !== 1 ? ` ✖${appliedFactor}`.length : 0)) +
// Weight or Size or ... %
Math.max(header[2].length, "100%".length) +
// Other columns
(0, sum_1.default)(Object.entries(otherNormalized).map(([k, v]) => Math.max(k.length, v.length)))))) !== null && _b !== void 0 ? _b : 0);
const maxTablesSideBySide = Math.trunc(((logging_1.stdout.columns || 80) - 10) / tableWidth);
const toPrint = {
islands: [...islands].map(([islandNo, shards]) => {
var _a, _b;
const dsn = islandNosToDsn.get(islandNo);
const totalWeight = (0, sumBy_1.default)(shards, (shard) => shard.weight);
const totalUnit = (_a = (0, first_1.default)(shards)) === null || _a === void 0 ? void 0 : _a.unit;
const totalOther = (0, mapValues_1.default)((_b = (0, first_1.default)(shards)) === null || _b === void 0 ? void 0 : _b.other, (_, k) => {
const values = shards
.map(({ other }) => parseFloat(other[k]))
.filter((v) => !isNaN(v));
return values.length > 0 ? (0, sum_1.default)(values).toString() : undefined;
});
return {
no: islandNo,
caption: `${(0, names_1.dsnShort)(dsn)} — ` + `${(0, pluralize_1.pluralize)(shards.length, "microshard")}`,
dsn: (0, names_1.dsnShort)(dsn),
header,
shards: shards.map(({ no, weight, appliedFactor, unit, otherNormalized }) => [
no.toString(),
(0, round_1.default)(weight / appliedFactor, 5).toString() +
(unit ? ` ${unit}` : "") +
(appliedFactor !== 1 ? ` ✖${appliedFactor}` : ""),
totalWeight !== 0
? `${((weight / totalWeight) * 100).toFixed(1)}%`
: "-",
...Object.values(otherNormalized),
]),
total: shards.length > 0
? [
"total",
totalWeight + (totalUnit ? ` ${totalUnit}` : ""),
"100%",
...Object.values(totalOther).map((v) => v !== null && v !== void 0 ? v : ""),
]
: undefined,
};
}),
total: `TOTAL ${grandTotalWeightColName.toUpperCase()}: ${grandTotalWeight}` +
(grandTotalUnit ? ` ${grandTotalUnit}` : "") +
`, ${(0, pluralize_1.pluralize)(islands.size, "island")}, ${(0, pluralize_1.pluralize)(grandTotalShards, "microshard")}`,
};
if (json) {
(0, logging_1.print)(JSON.stringify(toPrint, null, 2) + "\n");
return true;
}
for (const island of toPrint.islands) {
logging_1.print.section(island.caption);
if (island.shards.length === 0) {
(0, logging_1.print)((0, indent_1.indent)((0, table_1.table)([["No microshards"]])));
continue;
}
const tables = json ||
islands.size === 1 ||
maxTablesSideBySide === 0 ||
grandTotalShards + islands.size * 8 < (logging_1.stdout.rows || 25) ||
island.shards.length <= 4
? [island.shards]
: island.shards.length / maxTablesSideBySide < 2
? (0, chunk_1.default)(island.shards, 2)
: (0, chunkIntoN_1.chunkIntoN)(island.shards, maxTablesSideBySide);
(0, logging_1.print)(glueHorizontally(tables.map((tbl, tblNo) => (0, indent_1.indent)((0, table_1.table)((0, compact_1.default)([
island.header.map((cell) => chalk_1.default.bold(cell)),
...tbl.map((row) => row[0].trim() === "0"
? row.map((cell) => chalk_1.default.yellow(cell))
: row),
tblNo === 0 &&
island.total &&
island.total.map((cell) => chalk_1.default.bold(cell)),
]), {
drawHorizontalLine: (i, rowCount) => i === 0 ||
i === 1 ||
(tblNo === 0 && i === rowCount - 1) ||
i === rowCount,
})))));
}
(0, logging_1.print)(chalk_1.default.bgBlue(" " + chalk_1.default.whiteBright(toPrint.total) + " ") +
(verbose && !weightSql ? "" : " (try --verbose)"));
return true;
}
async function calcIslandWeights({ dsns, weightSql, verbose, }) {
try {
const pendingPrefix = "Calculating microshard sizes on: ";
const pendingDsns = new Set();
const islandNosToDsn = new Map([...dsns.entries()]);
const islands = new Map(await (0, promiseAllMap_1.promiseAllMap)([...islandNosToDsn.entries()], async ([islandNo, dsn]) => {
try {
pendingDsns.add((0, names_1.dsnShort)(dsn));
(0, logging_1.progress)(pendingPrefix + [...pendingDsns].join(", "));
const shards = await (0, weights_1.weights)({
dsn,
weightSql,
verbose,
});
return [islandNo, shards];
}
finally {
pendingDsns.delete((0, names_1.dsnShort)(dsn));
if (pendingDsns.size > 0) {
(0, logging_1.progress)(pendingPrefix + [...pendingDsns].join(", "));
}
}
}));
return { islandNosToDsn, islands };
}
finally {
logging_1.progress.clear();
}
}
function glueHorizontally(tables) {
var _a;
const rowsByTable = tables.map((table) => table.split("\n"));
const maxRows = (_a = (0, max_1.default)(rowsByTable.map((rows) => rows.length))) !== null && _a !== void 0 ? _a : 0;
for (const rows of rowsByTable) {
const maxWidth = rows[0].length;
for (let i = 0; i < maxRows; i++) {
rows[i] || (rows[i] = "");
rows[i] = rows[i].padEnd(maxWidth, " ");
}
}
const result = (0, range_1.default)(maxRows).map(() => []);
for (const rows of rowsByTable) {
for (const [i, col] of rows.entries()) {
result[i].push(col);
}
}
return result.map((lineArray) => lineArray.join("")).join("\n");
}
//# sourceMappingURL=actionList.js.map