Skip to content

Commit

Permalink
Use row streaming for pg so that all users aren't loaded into memory …
Browse files Browse the repository at this point in the history
…at once (#3205)

And only transfer the columns from users table that we care about
  • Loading branch information
hughns committed Sep 17, 2024
1 parent e0ea0b2 commit 18f1f69
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 10 deletions.
22 changes: 22 additions & 0 deletions tools/syn2mas/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tools/syn2mas/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"knex": "^3.0.1",
"log4js": "^6.9.1",
"pg": "^8.11.3",
"pg-query-stream": "^4.6.0",
"sqlite3": "^5.1.6",
"ts-command-line-args": "^2.5.1",
"yaml": "^2.3.3",
Expand Down
47 changes: 37 additions & 10 deletions tools/syn2mas/src/migrate.mts
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,7 @@ export async function migrate(): Promise<void> {
);
}

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

Expand Down Expand Up @@ -430,10 +424,43 @@ export async function migrate(): Promise<void> {
}
}
}

// this is a workaround to get the list of columns that we care about from the SUser type
const SUserColumns: Record<keyof SUser, undefined> = {
name: undefined,
password_hash: undefined,
admin: undefined,
is_guest: undefined,
deactivated: undefined,
creation_ts: undefined,
appservice_id: undefined,
};

// Get all Synapse users, except appservice owned users who don't need to be migrated
const synapseUserQuery = synapse
.select(Object.keys(SUserColumns) as (keyof SUser)[])
.from<SUser>("users")
.whereNull("appservice_id");

let synapseUsers = 0;
if (synapseConfig.database.name === "sqlite3") {
// SQLite doesn't support streaming
const synapseUserRows = (await synapseUserQuery) as unknown as SUser[];
for (const user of synapseUserRows) {
synapseUsers += 1;
await migrateUser(user);
}
} else {
// Stream users from the database
const synapseUserStream = synapseUserQuery.stream();
for await (const user of synapseUserStream) {
synapseUsers += 1;
await migrateUser(user as unknown as SUser);
}
}

log.info(
`Completed migration ${args.dryRun ? "dry-run " : ""}of ${
synapseUsers.length
} users with ${fatals} fatals and ${warnings.length} warnings:`,
`Completed migration ${args.dryRun ? "dry-run " : ""}of ${synapseUsers} users with ${fatals} fatals and ${warnings.length} warnings:`,
);
warnings.forEach((w) => log.warn(w));
if (fatals > 0) {
Expand Down

0 comments on commit 18f1f69

Please sign in to comment.