1
1
import { escapeIdentifier } from "pg" ;
2
2
3
+ import getLogger from "@cocalc/backend/logger" ;
4
+ import { envToInt } from "@cocalc/backend/misc/env-to-number" ;
3
5
import getPool from "@cocalc/database/pool" ;
4
6
import { SCHEMA } from "@cocalc/util/schema" ;
5
7
8
+ const log = getLogger ( "db:bulk-delete" ) ;
9
+ const D = log . debug ;
10
+
6
11
type Field =
7
12
| "project_id"
8
13
| "account_id"
9
14
| "target_project_id"
10
15
| "source_project_id" ;
11
16
17
+ const MAX_UTIL_PCT = envToInt ( "COCALC_DB_BULK_DELETE_MAX_UTIL_PCT" , 10 ) ;
18
+ // adjust the time limits: by default, we aim to keep the operation between 0.1 and 0.2 secs
19
+ const MAX_TIME_TARGET_MS = envToInt (
20
+ "COCALC_DB_BULK_DELETE_MAX_TIME_TARGET_MS" ,
21
+ 100 ,
22
+ ) ;
23
+ const MAX_TARGET_S = MAX_TIME_TARGET_MS / 1000 ;
24
+ const MIN_TARGET_S = MAX_TARGET_S / 2 ;
25
+ const DEFAULT_LIMIT = envToInt ( "COCALC_DB_BULK_DELETE_DEFAULT_LIMIT" , 16 ) ;
26
+ const MAX_LIMIT = envToInt ( "COCALC_DB_BULK_DELETE_MAX_LIMIT" , 32768 ) ;
27
+
12
28
interface Opts {
13
29
table : string ; // e.g. project_log, etc.
14
30
field : Field ; // for now, we only support a few
@@ -38,8 +54,8 @@ WHERE ${ID} IN (
38
54
}
39
55
40
56
export async function bulkDelete ( opts : Opts ) : Ret {
41
- const { table, field, value, id = "id" , maxUtilPct = 10 } = opts ;
42
- let { limit = 1024 } = opts ;
57
+ const { table, field, value, id = "id" , maxUtilPct = MAX_UTIL_PCT } = opts ;
58
+ let { limit = DEFAULT_LIMIT } = opts ;
43
59
// assert table name is a key in SCHEMA
44
60
if ( ! ( table in SCHEMA ) ) {
45
61
throw new Error ( `table ${ table } does not exist` ) ;
@@ -63,18 +79,16 @@ export async function bulkDelete(opts: Opts): Ret {
63
79
rowsDeleted += ret . rowCount ?? 0 ;
64
80
totalPgTimeS += dt ;
65
81
66
- // adjust the limit: we aim to keep the operation between 0.1 and 0.2 secs
67
- const next = dt > 0.2 ? limit / 2 : dt < 0.1 ? limit * 2 : limit ;
68
- limit = Math . max ( 1 , Math . min ( 32768 , Math . round ( next ) ) ) ;
82
+ const next =
83
+ dt > MAX_TARGET_S ? limit / 2 : dt < MIN_TARGET_S ? limit * 2 : limit ;
84
+ limit = Math . max ( 1 , Math . min ( MAX_LIMIT , Math . round ( next ) ) ) ;
69
85
70
86
// wait for a bit, but not more than 1 second ~ this aims for a max utilization of 10%
71
87
const waitS = Math . min ( 1 , dt * ( ( 100 - maxUtilPct ) / maxUtilPct ) ) ;
72
88
await new Promise ( ( done ) => setTimeout ( done , 1000 * waitS ) ) ;
73
89
totalWaitS += waitS ;
74
90
75
- // console.log(
76
- // `deleted ${ret.rowCount} | dt=${dt} | wait=${waitS} | limit=${limit}`,
77
- // );
91
+ D ( `deleted ${ ret . rowCount } | dt=${ dt } | wait=${ waitS } | limit=${ limit } ` ) ;
78
92
79
93
if ( ret . rowCount === 0 ) break ;
80
94
}
0 commit comments