db.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. const { Pool, native } = require( 'pg' );
  2. const cpus = require( 'os' ).cpus().length
  3. let maxConnections
  4. let clientOpts = {
  5. Client: native.Client,
  6. host: 'tfb-database',
  7. // host: 'host.docker.internal',
  8. // host: 'localhost',
  9. user: 'benchmarkdbuser',
  10. password: 'benchmarkdbpass',
  11. database: 'hello_world'
  12. };
  13. let pool
  14. let execute = async ( text, values ) => {
  15. try {
  16. return ( await pool.query( text, values || undefined ) ).rows;
  17. } catch( e ) {
  18. throw new Error( e )
  19. }
  20. }
  21. module.exports = {
  22. async init() {
  23. const client = new native.Client( clientOpts )
  24. await client.connect()
  25. const res = await client.query( 'SHOW max_connections' )
  26. maxConnections = res.rows[0].max_connections
  27. //1 worker per cpu, each worker pool gets a fraction of the max connections
  28. //only use 90% to avoid too many clients errors
  29. pool = new Pool( Object.assign( { ...clientOpts }, { max: Math.floor( maxConnections * 0.9 / cpus ) } ) )
  30. pool.on( 'error', ( err ) => {
  31. console.error( 'Unexpected client error', err )
  32. } )
  33. await client.end()
  34. },
  35. execute,
  36. randomId: () => Math.floor( Math.random() * 10000 ) + 1,
  37. randomUniqueIds: ( count ) => {
  38. const ids = {}
  39. for( let i = 0; i < count; i++ ) {
  40. let id = module.exports.randomId()
  41. if( ids[id] ) {
  42. for( let j = 0; j < 10000 - 1; j++ ) {
  43. if( !ids[id] ) break
  44. id++
  45. if( id > 10000 ) {
  46. id = 1
  47. }
  48. }
  49. }
  50. ids[id] = true
  51. }
  52. return Object.keys( ids )
  53. },
  54. allFortunes: async () =>
  55. execute( 'SELECT * FROM fortune' ),
  56. worldById: async ( id ) =>
  57. execute( `SELECT *
  58. FROM world
  59. WHERE id = $1`, [id] )
  60. .then( arr => arr[0] ),
  61. allWorlds: async () =>
  62. execute( 'SELECT * FROM world' ),
  63. bulkUpdateWorld: async worlds =>
  64. execute(
  65. `UPDATE world as w
  66. SET randomnumber = wc.randomnumber
  67. FROM (
  68. SELECT win.id, win.randomnumber
  69. FROM world wb,
  70. (VALUES ${
  71. //0 -> 1,2 ; 1 -> 3,4; 2 -> 5,6; 3 -> 7,8 ... = (i+1) * 2 - 1, (i+1) * 2
  72. worlds.map( ( _, i ) => `(\$${( i + 1 ) * 2 - 1}::int,$${( i + 1 ) * 2}::int)` ).join( ',' )
  73. }) AS win (id, randomnumber)
  74. WHERE wb.id = win.id
  75. FOR UPDATE
  76. ) as wc
  77. where w.id = wc.id`,
  78. worlds.map( world => [world.id, world.randomnumber] ).flat() )
  79. .then( () => worlds )
  80. }