From ebfd690602a8d64b69b936afb588e605a6e7c92c Mon Sep 17 00:00:00 2001 From: Cory Nathe Date: Fri, 27 Feb 2026 16:04:13 -0600 Subject: [PATCH 1/2] GitHub Issue 875: Assay Multi-File Transform Import Skips First Data Row (#7456) - TsvDataSerializer.exportData() to write first row regardless of if column headers written - Experiment module metric (assayRunsWithMultipleInputFiles) for count of the number of Luminex and Standard assay runs that were imported with > 1 data input file --- api/src/org/labkey/api/qc/TsvDataSerializer.java | 2 +- .../src/org/labkey/experiment/ExperimentModule.java | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/qc/TsvDataSerializer.java b/api/src/org/labkey/api/qc/TsvDataSerializer.java index 391d3aaa376..839ef801867 100644 --- a/api/src/org/labkey/api/qc/TsvDataSerializer.java +++ b/api/src/org/labkey/api/qc/TsvDataSerializer.java @@ -91,8 +91,8 @@ private List exportData(DataIteratorBuilder data, List columns, sep = "\t"; } pw.println(); - writeRow(row, columns, pw, tsvWriter); } + writeRow(row, columns, pw, tsvWriter); // GitHub Issue #875: write the first row regardless of whether we had a header or not // write the remaining rows while (iter.next()) diff --git a/experiment/src/org/labkey/experiment/ExperimentModule.java b/experiment/src/org/labkey/experiment/ExperimentModule.java index 90312720f61..04c6ee053f7 100644 --- a/experiment/src/org/labkey/experiment/ExperimentModule.java +++ b/experiment/src/org/labkey/experiment/ExperimentModule.java @@ -652,6 +652,17 @@ SELECT COUNT(DISTINCT DD.DomainURI) FROM JOIN exp.DomainDescriptor DD on PD.domainID = DD.domainId WHERE DD.domainUri LIKE ? AND D.rangeURI = ?""", "urn:lsid:%:" + ExpProtocol.AssayDomainTypes.Result.getPrefix() + ".%", PropertyType.FILE_LINK.getTypeUri()).getObject(Long.class)); + // metric to count the number of Luminex and Standard assay runs that were imported with > 1 data file + assayMetrics.put("assayRunsWithMultipleInputFiles", new SqlSelector(schema, """ + SELECT COUNT(*) FROM ( + SELECT sourceapplicationid, COUNT(*) AS count FROM exp.data + WHERE lsid NOT LIKE '%:RelatedFile.%' AND sourceapplicationid IN ( + SELECT rowid FROM exp.protocolapplication + WHERE lsid LIKE '%:SimpleProtocol.CoreStep' AND (protocollsid LIKE '%:LuminexAssayProtocol.%' OR protocollsid LIKE '%:GeneralAssayProtocol.%') + ) + GROUP BY sourceapplicationid + ) x WHERE count > 1""").getObject(Long.class)); + Map sampleLookupCountMetrics = new HashMap<>(); SQLFragment baseAssaySampleLookupSQL = new SQLFragment("SELECT COUNT(*) FROM exp.propertydescriptor WHERE (lookupschema = 'samples' OR (lookupschema = 'exp' AND lookupquery = 'Materials')) AND propertyuri LIKE ?"); From d2090d7cf2b2e80afed0394a29af7efb382eec4f Mon Sep 17 00:00:00 2001 From: Trey Chadick Date: Mon, 2 Mar 2026 11:44:19 -0800 Subject: [PATCH 2/2] Prevent ConcurrentModificationException in TempTableThread shutdown (#7463) --- api/src/org/labkey/api/data/TempTableTracker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/org/labkey/api/data/TempTableTracker.java b/api/src/org/labkey/api/data/TempTableTracker.java index d62b76b4c31..919b96633d3 100644 --- a/api/src/org/labkey/api/data/TempTableTracker.java +++ b/api/src/org/labkey/api/data/TempTableTracker.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.lang.ref.Cleaner; +import java.util.ArrayList; import java.util.Map; import java.util.TreeMap; import java.util.TreeSet; @@ -286,7 +287,8 @@ public void shutdownStarted() { synchronized(createdTableNames) { - for (TempTableTracker ttt : createdTableNames.values()) + // Copy createdTableNames.values() to prevent ConcurrentModificationException + for (TempTableTracker ttt : new ArrayList<>(createdTableNames.values())) { ttt.state.run(); }