@@ -267,6 +267,18 @@ private int getColByName(ResultSetMetaData rsmd, String source) throws SQLExcept
267267
268268 private long cumulativeTime ;
269269
270+ // Deferred DB operations: collected during parallel phases, flushed after
271+ private final java .util .concurrent .ConcurrentLinkedQueue <DeferredExpansion > deferredExpansions = new java .util .concurrent .ConcurrentLinkedQueue <>();
272+
273+ private static class DeferredExpansion {
274+ final ValueSet vs ;
275+ final ValueSetExpansionOutcome exp ;
276+ DeferredExpansion (ValueSet vs , ValueSetExpansionOutcome exp ) {
277+ this .vs = vs ;
278+ this .exp = exp ;
279+ }
280+ }
281+
270282 private void time (long start ) {
271283 cumulativeTime = cumulativeTime + (System .currentTimeMillis () - start );
272284 }
@@ -442,55 +454,75 @@ public void finishResources() {
442454 }
443455
444456 try {
445- PreparedStatement psql = con .prepareStatement ("Insert into Properties (Key, ResourceKey, Code, Uri, Description, Type) " +
446- "values (?, ?, ?, ?, ?, ?)" );
447- for (CodeSystem cs : codesystems ) {
448- for (PropertyComponent p : cs .getProperty ()) {
449- psql .setInt (1 , ++lastPropKey );
450- psql .setInt (2 , ((Integer ) cs .getUserData (UserDataNames .db_key )).intValue ());
451- bindString (psql , 3 , p .getCode ());
452- bindString (psql , 4 , p .getUri ());
453- bindString (psql , 5 , p .getDescription ());
454- bindString (psql , 6 , p .getType ().toCode ());
455- psql .executeUpdate ();
456- p .setUserData (UserDataNames .db_key , lastPropKey );
457+ boolean origAutoCommit = con .getAutoCommit ();
458+ try {
459+ con .setAutoCommit (false );
460+
461+ PreparedStatement psql = con .prepareStatement ("Insert into Properties (Key, ResourceKey, Code, Uri, Description, Type) " +
462+ "values (?, ?, ?, ?, ?, ?)" );
463+ for (CodeSystem cs : codesystems ) {
464+ for (PropertyComponent p : cs .getProperty ()) {
465+ psql .setInt (1 , ++lastPropKey );
466+ psql .setInt (2 , ((Integer ) cs .getUserData (UserDataNames .db_key )).intValue ());
467+ bindString (psql , 3 , p .getCode ());
468+ bindString (psql , 4 , p .getUri ());
469+ bindString (psql , 5 , p .getDescription ());
470+ bindString (psql , 6 , p .getType ().toCode ());
471+ psql .addBatch ();
472+ p .setUserData (UserDataNames .db_key , lastPropKey );
473+ }
457474 }
458- }
459- psql = con .prepareStatement ("Insert into Concepts (Key, ResourceKey, ParentKey, Code, Display, Definition) " +
460- "values (?, ?, ?, ?, ?, ?)" );
461- for (CodeSystem cs : codesystems ) {
462- addConcepts (cs , cs .getConcept (), psql , 0 );
463- }
464- psql = con .prepareStatement ("Insert into ConceptProperties (Key, ResourceKey, ConceptKey, PropertyKey, Code, Value) " +
465- "values (?, ?, ?, ?, ?, ?)" );
466- for (CodeSystem cs : codesystems ) {
467- addConceptProperties (cs , cs .getConcept (), psql );
468- }
469- psql = con .prepareStatement ("Insert into Designations (Key, ResourceKey, ConceptKey, UseSystem, UseCode, Lang, Value) " +
470- "values (?, ?, ?, ?, ?, ?, ?)" );
471- for (CodeSystem cs : codesystems ) {
472- addConceptDesignations (cs , cs .getConcept (), psql );
473- }
475+ psql .executeBatch ();
474476
475- psql = con .prepareStatement ("Insert into ConceptMappings (Key, ResourceKey, SourceSystem, SourceVersion, SourceCode, Relationship, TargetSystem, TargetVersion, TargetCode) " +
476- "values (?, ?, ?, ?, ?, ?, ?, ?, ?)" );
477- for (ConceptMap cm : mappings ) {
478- for (ConceptMapGroupComponent grp : cm .getGroup ()) {
479- for (SourceElementComponent src : grp .getElement ()) {
480- for (TargetElementComponent tgt : src .getTarget ()) {
481- psql .setInt (1 , ++lastMapKey );
482- psql .setInt (2 , ((Integer ) cm .getUserData (UserDataNames .db_key )).intValue ());
483- bindString (psql , 3 , grp .getSourceElement ().baseUrl ());
484- bindString (psql , 4 , grp .getSourceElement ().version ());
485- bindString (psql , 5 , src .getCode ());
486- bindString (psql , 6 , tgt .getRelationshipElement ().primitiveValue ());
487- bindString (psql , 7 , grp .getTargetElement ().baseUrl ());
488- bindString (psql , 8 , grp .getTargetElement ().version ());
489- bindString (psql , 9 , tgt .getCode ());
490- psql .executeUpdate ();
477+ psql = con .prepareStatement ("Insert into Concepts (Key, ResourceKey, ParentKey, Code, Display, Definition) " +
478+ "values (?, ?, ?, ?, ?, ?)" );
479+ for (CodeSystem cs : codesystems ) {
480+ addConcepts (cs , cs .getConcept (), psql , 0 );
481+ }
482+ psql .executeBatch ();
483+
484+ psql = con .prepareStatement ("Insert into ConceptProperties (Key, ResourceKey, ConceptKey, PropertyKey, Code, Value) " +
485+ "values (?, ?, ?, ?, ?, ?)" );
486+ for (CodeSystem cs : codesystems ) {
487+ addConceptProperties (cs , cs .getConcept (), psql );
488+ }
489+ psql .executeBatch ();
490+
491+ psql = con .prepareStatement ("Insert into Designations (Key, ResourceKey, ConceptKey, UseSystem, UseCode, Lang, Value) " +
492+ "values (?, ?, ?, ?, ?, ?, ?)" );
493+ for (CodeSystem cs : codesystems ) {
494+ addConceptDesignations (cs , cs .getConcept (), psql );
495+ }
496+ psql .executeBatch ();
497+
498+ psql = con .prepareStatement ("Insert into ConceptMappings (Key, ResourceKey, SourceSystem, SourceVersion, SourceCode, Relationship, TargetSystem, TargetVersion, TargetCode) " +
499+ "values (?, ?, ?, ?, ?, ?, ?, ?, ?)" );
500+ for (ConceptMap cm : mappings ) {
501+ for (ConceptMapGroupComponent grp : cm .getGroup ()) {
502+ for (SourceElementComponent src : grp .getElement ()) {
503+ for (TargetElementComponent tgt : src .getTarget ()) {
504+ psql .setInt (1 , ++lastMapKey );
505+ psql .setInt (2 , ((Integer ) cm .getUserData (UserDataNames .db_key )).intValue ());
506+ bindString (psql , 3 , grp .getSourceElement ().baseUrl ());
507+ bindString (psql , 4 , grp .getSourceElement ().version ());
508+ bindString (psql , 5 , src .getCode ());
509+ bindString (psql , 6 , tgt .getRelationshipElement ().primitiveValue ());
510+ bindString (psql , 7 , grp .getTargetElement ().baseUrl ());
511+ bindString (psql , 8 , grp .getTargetElement ().version ());
512+ bindString (psql , 9 , tgt .getCode ());
513+ psql .addBatch ();
514+ }
491515 }
492516 }
493517 }
518+ psql .executeBatch ();
519+
520+ con .commit ();
521+ } catch (SQLException e ) {
522+ try { con .rollback (); } catch (SQLException ignored ) {}
523+ throw e ;
524+ } finally {
525+ con .setAutoCommit (origAutoCommit );
494526 }
495527 } catch (SQLException e ) {
496528 errors .add (e .getMessage ());
@@ -502,31 +534,54 @@ public void finishResources() {
502534 }
503535
504536 public synchronized void recordExpansion (ValueSet vs , ValueSetExpansionOutcome exp ) throws SQLException {
505- long start = System .currentTimeMillis ();
506- try {
507- if (con == null ) {
508- return ;
509- }
510- if (exp == null || exp .getValueset () == null ) {
511- return ;
512- }
537+ // Queue for deferred execution to avoid SQLite lock contention during parallel phases
538+ deferredExpansions .add (new DeferredExpansion (vs , exp ));
539+ }
513540
541+ /** Flush all deferred DB operations. Call after parallel phase completes (single-threaded). */
542+ public synchronized void flushDeferredOperations () throws SQLException {
543+ if (con == null ) {
544+ // drain queue even if no connection
545+ while (deferredExpansions .poll () != null ) {}
546+ return ;
547+ }
548+ boolean origAutoCommit = con .getAutoCommit ();
549+ try {
550+ con .setAutoCommit (false );
514551 PreparedStatement psql = con .prepareStatement ("Insert into ValueSet_Codes (Key, ResourceKey, ValueSetUri, ValueSetVersion, System, Version, Code, Display) " +
515552 "values (?, ?, ?, ?, ?, ?, ?, ?)" );
516- for (ValueSetExpansionContainsComponent e : exp .getValueset ().getExpansion ().getContains ()) {
517- addContains (vs , e , psql );
553+ DeferredExpansion de ;
554+ int batchCount = 0 ;
555+ while ((de = deferredExpansions .poll ()) != null ) {
556+ if (de .exp == null || de .exp .getValueset () == null ) {
557+ continue ;
558+ }
559+ long start = System .currentTimeMillis ();
560+ try {
561+ for (ValueSetExpansionContainsComponent e : de .exp .getValueset ().getExpansion ().getContains ()) {
562+ batchCount = addContainsBatch (de .vs , e , psql , batchCount );
563+ }
564+ } catch (SQLException e ) {
565+ errors .add (e .getMessage ());
566+ if (debug ) {
567+ e .printStackTrace ();
568+ }
569+ }
570+ time (start );
518571 }
519- } catch (SQLException e ) {
520- errors .add (e .getMessage ());
521- if (debug ) {
522- e .printStackTrace ();
572+ if (batchCount > 0 ) {
573+ psql .executeBatch ();
523574 }
575+ con .commit ();
576+ } catch (SQLException e ) {
577+ try { con .rollback (); } catch (SQLException ignored ) {}
578+ throw e ;
579+ } finally {
580+ con .setAutoCommit (origAutoCommit );
524581 }
525- time (start );
526582 }
527583
528-
529- private void addContains (ValueSet vs , ValueSetExpansionContainsComponent e , PreparedStatement psql ) throws SQLException {
584+ private int addContainsBatch (ValueSet vs , ValueSetExpansionContainsComponent e , PreparedStatement psql , int batchCount ) throws SQLException {
530585 if (vs .hasUserData (UserDataNames .db_key )) {
531586 psql .setInt (1 , ++lastVSKey );
532587 psql .setInt (2 , ((Integer ) vs .getUserData (UserDataNames .db_key )).intValue ());
@@ -536,11 +591,16 @@ private void addContains(ValueSet vs, ValueSetExpansionContainsComponent e, Prep
536591 bindString (psql , 6 , e .getVersion ());
537592 bindString (psql , 7 , e .getCode ());
538593 bindString (psql , 8 , e .getDisplay ());
539- psql .executeUpdate ();
594+ psql .addBatch ();
595+ batchCount ++;
596+ if (batchCount % 5000 == 0 ) {
597+ psql .executeBatch ();
598+ }
540599 for (ValueSetExpansionContainsComponent c : e .getContains ()) {
541- addContains (vs , c , psql );
600+ batchCount = addContainsBatch (vs , c , psql , batchCount );
542601 }
543602 }
603+ return batchCount ;
544604 }
545605
546606 private void addConcepts (CodeSystem cs , List <ConceptDefinitionComponent > list , PreparedStatement psql , int parent ) throws SQLException {
@@ -556,7 +616,7 @@ private void addConcepts(CodeSystem cs, List<ConceptDefinitionComponent> list, P
556616 bindString (psql , 4 , cd .getCode ());
557617 bindString (psql , 5 , cd .getDisplay ());
558618 bindString (psql , 6 , cd .getDefinition ());
559- psql .executeUpdate ();
619+ psql .addBatch ();
560620 cd .setUserData (UserDataNames .db_key , lastConceptKey );
561621 addConcepts (cs , cd .getConcept (), psql , lastConceptKey );
562622 }
@@ -578,7 +638,7 @@ private void addConceptProperties(CodeSystem cs, List<ConceptDefinitionComponent
578638 }
579639 bindString (psql , 5 , p .getCode ());
580640 bindString (psql , 6 , p .getValue () == null ? p .getValue ().primitiveValue () : null );
581- psql .executeUpdate ();
641+ psql .addBatch ();
582642 p .setUserData (UserDataNames .db_key , lastCPropKey );
583643 }
584644 addConceptProperties (cs , cd .getConcept (), psql );
@@ -602,7 +662,7 @@ private void addConceptDesignations(CodeSystem cs, List<ConceptDefinitionCompone
602662 }
603663 bindString (psql , 6 , p .getLanguage ());
604664 bindString (psql , 7 , p .getValue ());
605- psql .executeUpdate ();
665+ psql .addBatch ();
606666 p .setUserData (UserDataNames .db_key , lastDesgKey );
607667 }
608668 addConceptDesignations (cs , cd .getConcept (), psql );
0 commit comments