Skip to content

Commit 18f1f69

Browse files
authored
Use row streaming for pg so that all users aren't loaded into memory at once (#3205)
And only transfer the columns from users table that we care about
1 parent e0ea0b2 commit 18f1f69

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

tools/syn2mas/package-lock.json

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/syn2mas/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"knex": "^3.0.1",
5858
"log4js": "^6.9.1",
5959
"pg": "^8.11.3",
60+
"pg-query-stream": "^4.6.0",
6061
"sqlite3": "^5.1.6",
6162
"ts-command-line-args": "^2.5.1",
6263
"yaml": "^2.3.3",

tools/syn2mas/src/migrate.mts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,7 @@ export async function migrate(): Promise<void> {
192192
);
193193
}
194194

195-
// Get all Synapse users, except appservice owned users who don't need to be migrated
196-
const synapseUsers = await synapse
197-
.select("*")
198-
.from<SUser>("users")
199-
.whereNull("appservice_id");
200-
log.info(`Found ${synapseUsers.length} users in Synapse`);
201-
for (const user of synapseUsers) {
195+
async function migrateUser(user: SUser): Promise<void> {
202196
const localpart = user.name.split(":")[0].substring(1);
203197
log.info(`Processing user ${user.name} as ${localpart}`);
204198

@@ -430,10 +424,43 @@ export async function migrate(): Promise<void> {
430424
}
431425
}
432426
}
427+
428+
// this is a workaround to get the list of columns that we care about from the SUser type
429+
const SUserColumns: Record<keyof SUser, undefined> = {
430+
name: undefined,
431+
password_hash: undefined,
432+
admin: undefined,
433+
is_guest: undefined,
434+
deactivated: undefined,
435+
creation_ts: undefined,
436+
appservice_id: undefined,
437+
};
438+
439+
// Get all Synapse users, except appservice owned users who don't need to be migrated
440+
const synapseUserQuery = synapse
441+
.select(Object.keys(SUserColumns) as (keyof SUser)[])
442+
.from<SUser>("users")
443+
.whereNull("appservice_id");
444+
445+
let synapseUsers = 0;
446+
if (synapseConfig.database.name === "sqlite3") {
447+
// SQLite doesn't support streaming
448+
const synapseUserRows = (await synapseUserQuery) as unknown as SUser[];
449+
for (const user of synapseUserRows) {
450+
synapseUsers += 1;
451+
await migrateUser(user);
452+
}
453+
} else {
454+
// Stream users from the database
455+
const synapseUserStream = synapseUserQuery.stream();
456+
for await (const user of synapseUserStream) {
457+
synapseUsers += 1;
458+
await migrateUser(user as unknown as SUser);
459+
}
460+
}
461+
433462
log.info(
434-
`Completed migration ${args.dryRun ? "dry-run " : ""}of ${
435-
synapseUsers.length
436-
} users with ${fatals} fatals and ${warnings.length} warnings:`,
463+
`Completed migration ${args.dryRun ? "dry-run " : ""}of ${synapseUsers} users with ${fatals} fatals and ${warnings.length} warnings:`,
437464
);
438465
warnings.forEach((w) => log.warn(w));
439466
if (fatals > 0) {

0 commit comments

Comments
 (0)