query.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Column } from 'mol-data/db';
  7. import { CifWriter } from 'mol-io/writer/cif';
  8. import Writer from 'mol-io/writer/writer';
  9. import { StructureQuery, StructureSelection } from 'mol-model/structure';
  10. import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif';
  11. import { now, Progress } from 'mol-task';
  12. import { ConsoleLogger } from 'mol-util/console-logger';
  13. import { PerformanceMonitor } from 'mol-util/performance-monitor';
  14. import Config from '../config';
  15. import Version from '../version';
  16. import { Job } from './jobs';
  17. import { getStructure, StructureWrapper } from './structure-wrapper';
  18. import CifField = CifWriter.Field
  19. export interface Stats {
  20. structure: StructureWrapper,
  21. queryTimeMs: number,
  22. encodeTimeMs: number
  23. }
  24. const perf = new PerformanceMonitor();
  25. export async function resolveJob(job: Job, writer: Writer) {
  26. ConsoleLogger.logId(job.id, 'Query', 'Starting.');
  27. const wrappedStructure = await getStructure(job);
  28. perf.start('query');
  29. const structure = job.queryDefinition.structureTransform
  30. ? await job.queryDefinition.structureTransform(job.normalizedParams, wrappedStructure.structure)
  31. : wrappedStructure.structure;
  32. const query = job.queryDefinition.query(job.normalizedParams, structure);
  33. const result = StructureSelection.unionStructure(StructureQuery.run1(query, structure));
  34. perf.end('query');
  35. ConsoleLogger.logId(job.id, 'Query', 'Query finished.');
  36. const encoder = CifWriter.createEncoder({ binary: job.responseFormat.isBinary, encoderName: `ModelServer ${Version}` });
  37. perf.start('encode');
  38. encoder.startDataBlock(structure.units[0].model.label.toUpperCase());
  39. encoder.writeCategory(_model_server_result, [job]);
  40. encoder.writeCategory(_model_server_params, [job]);
  41. // encoder.setFilter(mmCIF_Export_Filters.onlyPositions);
  42. encode_mmCIF_categories(encoder, result);
  43. // encoder.setFilter();
  44. perf.end('encode');
  45. ConsoleLogger.logId(job.id, 'Query', 'Encoded.');
  46. const stats: Stats = {
  47. structure: wrappedStructure,
  48. queryTimeMs: perf.time('query'),
  49. encodeTimeMs: perf.time('encode')
  50. };
  51. encoder.writeCategory(_model_server_stats, [stats]);
  52. encoder.encode();
  53. encoder.writeTo(writer);
  54. ConsoleLogger.logId(job.id, 'Query', 'Written.');
  55. }
  56. const maxTime = Config.maxQueryTimeInMs;
  57. export function abortingObserver(p: Progress) {
  58. if (now() - p.root.progress.startedTime > maxTime) {
  59. p.requestAbort(`Exceeded maximum allowed time for a query (${maxTime}ms)`);
  60. }
  61. }
  62. function string<T>(name: string, str: (data: T, i: number) => string, isSpecified?: (data: T) => boolean): CifField<number, T> {
  63. if (isSpecified) {
  64. return CifField.str(name, (i, d) => str(d, i), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKind.Present : Column.ValueKind.NotPresent });
  65. }
  66. return CifField.str(name, (i, d) => str(d, i));
  67. }
  68. function int32<T>(name: string, value: (data: T) => number): CifField<number, T> {
  69. return CifField.int(name, (i, d) => value(d));
  70. }
  71. const _model_server_result_fields: CifField<number, Job>[] = [
  72. string<Job>('job_id', ctx => '' + ctx.id),
  73. string<Job>('datetime_utc', ctx => ctx.datetime_utc),
  74. string<Job>('server_version', ctx => Version),
  75. string<Job>('query_name', ctx => ctx.queryDefinition.name),
  76. string<Job>('source_id', ctx => ctx.sourceId),
  77. string<Job>('entry_id', ctx => ctx.entryId),
  78. ];
  79. const _model_server_params_fields: CifField<number, string[]>[] = [
  80. string<string[]>('name', (ctx, i) => ctx[i][0]),
  81. string<string[]>('value', (ctx, i) => ctx[i][1])
  82. ];
  83. const _model_server_stats_fields: CifField<number, Stats>[] = [
  84. int32<Stats>('io_time_ms', ctx => ctx.structure.info.readTime | 0),
  85. int32<Stats>('parse_time_ms', ctx => ctx.structure.info.parseTime | 0),
  86. int32<Stats>('create_model_time_ms', ctx => ctx.structure.info.createModelTime | 0),
  87. int32<Stats>('query_time_ms', ctx => ctx.queryTimeMs | 0),
  88. int32<Stats>('encode_time_ms', ctx => ctx.encodeTimeMs | 0)
  89. ];
  90. const _model_server_result: CifWriter.Category<Job> = {
  91. name: 'model_server_result',
  92. instance: (job) => ({ data: job, fields: _model_server_result_fields, rowCount: 1 })
  93. };
  94. const _model_server_params: CifWriter.Category<Job> = {
  95. name: 'model_server_params',
  96. instance(job) {
  97. const params: string[][] = [];
  98. for (const k of Object.keys(job.normalizedParams)) {
  99. params.push([k, '' + job.normalizedParams[k]]);
  100. }
  101. return {
  102. data: params,
  103. fields: _model_server_params_fields,
  104. rowCount: params.length
  105. }
  106. }
  107. };
  108. const _model_server_stats: CifWriter.Category<Stats> = {
  109. name: 'model_server_stats',
  110. instance: (stats) => ({ data: stats, fields: _model_server_stats_fields, rowCount: 1 })
  111. }