Skip to content

Commit

Permalink
Update PostgreSQL reporting and PostgreSQL testing. (terraforming-mar…
Browse files Browse the repository at this point in the history
  • Loading branch information
kberg authored Sep 25, 2024
1 parent d5efb41 commit 6161b31
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 36 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"test": "npm run test:server && npm run test:client",
"test:server": "ts-mocha -p tests/tsconfig.json -r tests/utils/setup.ts \"tests/*.spec.ts\" \"tests/!(client|integration)/**/*.spec.ts\"",
"test:integration": "ts-mocha -p tests/tsconfig.json \"tests/integration/**/*.spec.ts\"",
"test:postgresql": "ts-mocha -p tests/tsconfig.json \"tests/integration/PostgreSQL.spec.ts\"",
"test:client": "cross-env NODE_ENV=development mochapack --require tests/client/components/setup.ts \"tests/client/**/*.spec.ts\"",
"test:client:watch": "cross-env NODE_ENV=development mochapack --watch --require tests/client/components/setup.ts \"tests/client/**/*.spec.ts\"",
"cover": "nyc ts-mocha -p tests/tsconfig.json -r tests/utils/setup.ts \"tests/*.spec.ts\" \"tests/!(client)/**/*.spec.ts\"",
Expand Down
43 changes: 13 additions & 30 deletions src/server/database/PostgreSQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import {GameId, ParticipantId, isGameId, safeCast} from '../../common/Types';
import {SerializedGame} from '../SerializedGame';
import {daysAgoToSeconds} from './utils';
import {GameIdLedger} from './IDatabase';
import {oneWayDifference} from '../../common/utils/utils';

type StoredSerializedGame = Omit<SerializedGame, 'gameOptions' | 'gameLog'> & {logLength: number};

export const POSTGRESQL_TABLES = ['game', 'games', 'game_results', 'participants', 'completed_game'] as const;

export class PostgreSQL implements IDatabase {
private databaseName: string | undefined = undefined; // Use this only for stats.

Expand Down Expand Up @@ -292,7 +293,6 @@ export class PostgreSQL implements IDatabase {
const gameJSON = JSON.stringify(storedSerialized);

this.statistics.saveCount++;
if (game.gameOptions.undoOption) logForUndo(game.id, 'start save', game.lastSaveId);
try {
await this.client.query('BEGIN');

Expand Down Expand Up @@ -338,8 +338,6 @@ export class PostgreSQL implements IDatabase {
await this.storeParticipants({gameId: game.id, participantIds: participantIds});
}

if (game.gameOptions.undoOption) logForUndo(game.id, 'increment save id, now', game.lastSaveId);

await this.client.query('COMMIT');
} catch (err) {
await this.client.query('ROLLBACK');
Expand All @@ -354,13 +352,7 @@ export class PostgreSQL implements IDatabase {
// Should this be an error?
return;
}
logForUndo(gameId, 'deleting', rollbackCount, 'saves');
const first = await this.getSaveIds(gameId);
const res = await this.client.query('DELETE FROM games WHERE ctid IN (SELECT ctid FROM games WHERE game_id = $1 ORDER BY save_id DESC LIMIT $2)', [gameId, rollbackCount]);
logForUndo(gameId, 'deleted', res?.rowCount, 'rows');
const second = await this.getSaveIds(gameId);
logForUndo(gameId, 'second', second);
logForUndo(gameId, 'Rollback difference', oneWayDifference(first, second));
await this.client.query('DELETE FROM games WHERE ctid IN (SELECT ctid FROM games WHERE game_id = $1 ORDER BY save_id DESC LIMIT $2)', [gameId, rollbackCount]);
}

public async storeParticipants(entry: GameIdLedger): Promise<void> {
Expand All @@ -386,17 +378,14 @@ export class PostgreSQL implements IDatabase {
'save-conflict-undo-count': this.statistics.saveConflictUndoCount,
};

const dbsizes = await this.client.query(`
SELECT
pg_size_pretty(pg_total_relation_size('games')) as game_size,
pg_size_pretty(pg_total_relation_size('game_results')) as game_results_size,
pg_size_pretty(pg_total_relation_size('participants')) as participants_size,
pg_size_pretty(pg_database_size($1)) as db_size
`, [this.databaseName]);

map['size-bytes-games'] = dbsizes.rows[0].game_size;
map['size-bytes-game-results'] = dbsizes.rows[0].game_results_size;
map['size-bytes-participants'] = dbsizes.rows[0].participants_size;
const columns = POSTGRESQL_TABLES.map((table_name) => `pg_size_pretty(pg_total_relation_size('${table_name}')) as ${table_name}_size`);
const dbsizes = await this.client.query(`SELECT ${columns.join(', ')}, pg_size_pretty(pg_database_size('${this.databaseName}')) as db_size`);

function varz(x: string) {
return x.replaceAll('_', '-');
}

POSTGRESQL_TABLES.forEach((table) => map['size-bytes-' + varz(table)] = dbsizes.rows[0][table + '_size']);
map['size-bytes-database'] = dbsizes.rows[0].db_size;

// Using count(*) is inefficient, but the estimates from here
Expand All @@ -409,16 +398,10 @@ export class PostgreSQL implements IDatabase {
// VACUUM (VERBOSE) shows a fairly reasonable vacumm (no rows locked, for instance),
// so it's not clear why those wrong. But these select count(*) commands seem pretty quick
// in testing. :fingers-crossed:
for (const table of ['games', 'game_results', 'participants']) {
for (const table of POSTGRESQL_TABLES) {
const result = await this.client.query('select count(*) as rowcount from ' + table);
map['rows-' + table] = result.rows[0].rowcount;
map['rows-' + varz(table)] = result.rows[0].rowcount;
}
return map;
}
}

function logForUndo(gameId: string, ...message: any[]) {
if (process.env.LOG_FOR_UNDO) {
console.error(['TRACKING:', gameId, ...message]);
}
}
8 changes: 7 additions & 1 deletion tests/integration/PostgreSQL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ sudo -u postgres psql -U postgres
Edit the authoriation rules configuration file

```
sudo nano /etc/postgresql/12/main/pg_hba.conf
sudo nano /etc/postgresql/16/main/pg_hba.conf
```

And add this line to the bottom
Expand Down Expand Up @@ -59,3 +59,9 @@ Now you can run the postgresql test.
```
npm run test:integration
```

or juts

```
npm run test:postgresql
```
15 changes: 10 additions & 5 deletions tests/integration/PostgreSQL.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {describeDatabaseSuite} from '../database/databaseSuite';
import {ITestDatabase, Status} from '../database/ITestDatabase';
import {IGame} from '../../src/server/IGame';
import {Game} from '../../src/server/Game';
import {PostgreSQL} from '../../src/server/database/PostgreSQL';
import {PostgreSQL, POSTGRESQL_TABLES} from '../../src/server/database/PostgreSQL';
import {TestPlayer} from '../TestPlayer';
import {SelectOption} from '../../src/server/inputs/SelectOption';
import {Phase} from '../../src/common/Phase';
Expand Down Expand Up @@ -48,13 +48,18 @@ class TestPostgreSQL extends PostgreSQL implements ITestDatabase {
response['size-bytes-database'] = 'any';
response['size-bytes-participants'] = 'any';

const extraFields = ['rows-game', 'size-bytes-game', 'rows-completed-game', 'size-bytes-completed-game'];
for (const field of extraFields) {
expect(response[field], 'For ' + field).is.not.undefined;
delete response[field];
}
return response;
}

public async afterEach() {
await this.client.query('DROP TABLE IF EXISTS games');
await this.client.query('DROP TABLE IF EXISTS game_results');
await this.client.query('DROP TABLE IF EXISTS participants');
for (const table of POSTGRESQL_TABLES) {
await this.client.query('DROP TABLE IF EXISTS ' + table);
}
}

public getStatistics() {
Expand Down Expand Up @@ -105,7 +110,7 @@ describeDatabaseSuite({
'pool-total-count': 1,
'pool-idle-count': 1,
'pool-waiting-count': 0,
'rows-game_results': '0',
'rows-game-results': '0',
'rows-games': '0',
'rows-participants': '0',
'size-bytes-games': 'any',
Expand Down

0 comments on commit 6161b31

Please sign in to comment.