run-payroll-source-index-concurrency.mjs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. // Explicit manual runner. Creates only a private copied schema and a short-lived
  2. // operator-restricted diagnostic endpoint; drops both in finally blocks.
  3. import fs from 'node:fs';
  4. import {randomBytes} from 'node:crypto';
  5. import {withGateway} from '../../perf/speed-round3-2026-11-10/server-util.mjs';
  6. import {installPayrollSourceIndexConcurrency,payrollSourceIndexConcurrentAcceptance,payrollSourceIndexWriterCosts,payrollSourceIndexMembershipAcceptance} from './payroll-source-index-concurrency.mjs';
  7. const schema='speed3_concurrency_'+randomBytes(5).toString('hex'),company='7pIbDBJmKx';
  8. const definitions=JSON.parse(fs.readFileSync('/Users/mac/.local/state/xiaoshu/cloud-releases/2026-11-10-speed-round3/original-definitions.json','utf8'));
  9. const functions=['xs_payroll_time','xs_payroll_sources','xs_payroll_source_version','xs_payroll_cutoff_snapshot'].map(name=>definitions.find(d=>d.proname===name).definition.replaceAll('public.',schema+'.')).join(';\n');
  10. const tables=['CommonModel','CourseAppointment','LessonRecord','LessonRecordFact','MemoryPracticeRecord','TeachingCompensationRule','CourseTeachingProfile','CoachPayRate','ReviewRewardIncome'];
  11. const config={schema,company,tables,functions,incrementalSql:fs.readFileSync('scripts/sql/payroll-incremental-reads.sql','utf8'),indexSql:fs.readFileSync('scripts/sql/payroll-source-index.sql','utf8')};
  12. async function run(params){
  13. if(params.action==='setup'){
  14. const started=Date.now();
  15. await Psql.tx(async tx=>{
  16. await tx.none('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
  17. await tx.none('CREATE SCHEMA '+config.schema);await tx.none('REVOKE ALL ON SCHEMA '+config.schema+' FROM PUBLIC');
  18. await tx.none('SET LOCAL search_path='+config.schema+',public');await tx.none("SET LOCAL statement_timeout='120s';SET LOCAL jit=off");
  19. for(const table of config.tables)await tx.none('CREATE TABLE "'+table+'" AS SELECT * FROM public."'+table+'" WHERE company=$1'+(table==='CommonModel'?' AND "modelId" IN(54,59,60)':''),[config.company]);
  20. for(const table of config.tables)await tx.none('CREATE UNIQUE INDEX ON "'+table+'" ("objectId")');
  21. for(const table of ['CourseAppointment','LessonRecord','MemoryPracticeRecord'])await tx.none('CREATE INDEX ON "'+table+'" (company,id)');
  22. await tx.none('CREATE INDEX ON "CommonModel" (company,"modelId","itemId","objectId");CREATE INDEX ON "CommonModel" (company,"modelId",("generalId"::text));CREATE INDEX ON "CommonModel" (company,"modelId","generalId")');
  23. await tx.none(config.functions);
  24. // An empty private digest table with its real primary key is filled by the
  25. // real incremental migration, never copied or replaced with ready stubs.
  26. await tx.none('CREATE TABLE "PayrollReadDigest"(kind text NOT NULL,company text NOT NULL,"objectId" text NOT NULL,model numeric,hash text NOT NULL,PRIMARY KEY(kind,company,"objectId"))');
  27. for(const table of config.tables)await tx.none('ANALYZE "'+table+'"');
  28. });
  29. const ready=await installPayrollSourceIndexConcurrency(Psql,config);
  30. return {schema:config.schema,setupMs:Date.now()-started,...ready};
  31. }
  32. if(params.action==='race')return payrollSourceIndexConcurrentAcceptance(Psql,config);
  33. if(params.action==='membership')return payrollSourceIndexMembershipAcceptance(Psql,config);
  34. if(params.action==='writers')return payrollSourceIndexWriterCosts(Psql,config);
  35. if(params.action==='drop'){await Psql.none('DROP SCHEMA IF EXISTS '+config.schema+' CASCADE');return{dropped:true};}
  36. throw Error('Unknown fixed private-clone diagnostic');
  37. }
  38. const source='const config='+JSON.stringify(config)+';\n'+installPayrollSourceIndexConcurrency.toString()+'\n'+payrollSourceIndexConcurrentAcceptance.toString()+'\n'+payrollSourceIndexWriterCosts.toString()+'\n'+payrollSourceIndexMembershipAcceptance.toString()+'\n'+run.toString();
  39. const result={schema};
  40. await withGateway(source,async call=>{
  41. try{
  42. for(const action of ['setup','race','membership','writers']){
  43. result[action]=await call({action});
  44. fs.writeFileSync('tmp/speed-round3-2026-11-10/source-index-concurrency.json',JSON.stringify(result,null,2),{mode:0o600});
  45. console.log(JSON.stringify({action,result:result[action]}));
  46. }
  47. }finally{result.cleanup=await call({action:'drop'});fs.writeFileSync('tmp/speed-round3-2026-11-10/source-index-concurrency.json',JSON.stringify(result,null,2),{mode:0o600});console.log(JSON.stringify({action:'drop',...result.cleanup}));}
  48. });