Path: blob/master/src/packages/hub/migrate-bookmarks.ts
1709 views
/*1* This file is part of CoCalc: Copyright © 2024 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { delay } from "awaiting";67import { conat } from "@cocalc/backend/conat/conat";8import { dkv } from "@cocalc/backend/conat/sync";9import {10CONAT_BOOKMARKS_KEY,11STARRED_FILES,12} from "@cocalc/util/consts/bookmarks";13import { getLogger } from "./logger";14import getPool from "@cocalc/database/pool";1516const L = getLogger("hub:migrate-bookmarks");1718const BATCH_SIZE = 100;19const MIGRATION_DELAY = 500; // ms between batches to avoid database saturation2021export async function migrateBookmarksToConat(): Promise<void> {22L.info("Starting migration of bookmarks to conat...");2324const pool = getPool();25let totalMigrated = 0;26let batchCount = 0;2728while (true) {29try {30// Query for a batch of bookmark entries31const { rows } = await pool.query(32`33SELECT id, account_id, project_id, stars34FROM bookmarks35WHERE type = $136ORDER BY id37LIMIT $238`,39[STARRED_FILES, BATCH_SIZE],40);4142if (rows.length === 0) {43L.info(44`Migration completed. Total migrated: ${totalMigrated} bookmarks`,45);46break;47}4849batchCount++;50L.info(`Processing batch ${batchCount} with ${rows.length} bookmarks...`);5152// Process each bookmark in the batch53const processedIds: string[] = [];5455for (const row of rows) {56try {57const { id, account_id, project_id, stars } = row;5859if (!account_id || !project_id || !Array.isArray(stars)) {60L.warn(61`Skipping invalid bookmark ${id}: account_id=${account_id}, project_id=${project_id}, stars=${stars}`,62);63processedIds.push(id);64continue;65}6667// Get or create conat DKV for this account68const bookmarks = await dkv<string[]>({69name: CONAT_BOOKMARKS_KEY,70account_id,71client: conat(),72});7374// Set the starred files for this project75bookmarks.set(project_id, stars);76L.debug(77`Migrated bookmark ${id} for account ${account_id}, project ${project_id} with ${stars.length} stars`,78);7980processedIds.push(id);81totalMigrated++;82} catch (err) {83L.error(`Failed to migrate bookmark ${row.id}: ${err}`);84// Still add to processedIds so we don't get stuck on this one85processedIds.push(row.id);86}87}8889// Delete the processed bookmarks from the database90if (processedIds.length > 0) {91await pool.query(`DELETE FROM bookmarks WHERE id = ANY($1)`, [92processedIds,93]);94L.debug(`Deleted ${processedIds.length} bookmarks from database`);95}9697// Wait between batches to avoid database saturation98if (rows.length === BATCH_SIZE) {99L.debug(`Waiting ${MIGRATION_DELAY}ms before next batch...`);100await delay(MIGRATION_DELAY);101}102} catch (err) {103L.error(`Error in migration batch: ${err}`);104// Wait longer on error before retrying105await delay(MIGRATION_DELAY * 3);106}107}108109L.info("Bookmark migration to conat completed successfully");110}111112113