Skip to content
30 changes: 23 additions & 7 deletions api/src/org/labkey/api/audit/data/ExperimentAuditColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,27 @@
import org.labkey.api.exp.api.ExpObject;
import org.labkey.api.util.HtmlString;
import org.labkey.api.util.LinkBuilder;
import org.labkey.api.util.Pair;
import org.labkey.api.view.ActionURL;
import org.labkey.api.writer.HtmlWriter;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

public abstract class ExperimentAuditColumn<ObjectType extends ExpObject> extends DataColumn
{
protected ColumnInfo _containerId;
protected ColumnInfo _defaultName;
// The same object typically repeats across rows
private final Map<CacheKey, Optional<ExpLink<ObjectType>>> _expValues = new HashMap<>();

public static final String KEY_SEPARATOR = "~~KEYSEP~~";

protected record ExpLink<T extends ExpObject>(T object, @Nullable ActionURL url) {}

private record CacheKey(Object boundValue, @Nullable String containerId) {}

public ExperimentAuditColumn(ColumnInfo col, ColumnInfo containerId, ColumnInfo defaultName)
{
super(col);
Expand All @@ -61,15 +69,23 @@ protected Container getContainer(RenderContext ctx)
}

@Nullable
protected abstract Pair<ObjectType, ActionURL> getExpValue(RenderContext ctx);
protected abstract ExpLink<ObjectType> getExpValue(RenderContext ctx);

@Nullable
private ExpLink<ObjectType> getCachedExpValue(RenderContext ctx)
{
Container c = getContainer(ctx);
CacheKey key = new CacheKey(getBoundColumn().getValue(ctx), c == null ? null : c.getId());
return _expValues.computeIfAbsent(key, _ -> Optional.ofNullable(getExpValue(ctx))).orElse(null);
}

@Override
public Object getDisplayValue(RenderContext ctx)
{
Pair<ObjectType, ActionURL> value = getExpValue(ctx);
ExpLink<ObjectType> value = getCachedExpValue(ctx);
if (value != null)
{
return value.first.getName();
return value.object().getName();
}

if (_defaultName != null)
Expand Down Expand Up @@ -101,10 +117,10 @@ public boolean isFilterable()
@Override
public void renderGridCellContents(RenderContext ctx, HtmlWriter out)
{
Pair<ObjectType, ActionURL> value = getExpValue(ctx);
if (value != null && value.second != null)
ExpLink<ObjectType> value = getCachedExpValue(ctx);
if (value != null && value.url() != null)
{
out.write(LinkBuilder.simpleLink(value.first.getName(), value.second));
out.write(LinkBuilder.simpleLink(value.object().getName(), value.url()));
return;
}

Expand Down
5 changes: 2 additions & 3 deletions api/src/org/labkey/api/audit/data/ProtocolColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import org.labkey.api.exp.api.ExperimentService;
import org.labkey.api.exp.api.ExperimentUrls;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.Pair;
import org.labkey.api.view.ActionURL;

import static org.labkey.api.util.IntegerUtils.asLongElseNull;
Expand All @@ -44,7 +43,7 @@ public ProtocolColumn(ColumnInfo col, ColumnInfo containerId, @Nullable ColumnIn

@Nullable
@Override
protected Pair<ExpProtocol, ActionURL> getExpValue(RenderContext ctx)
protected ExpLink<ExpProtocol> getExpValue(RenderContext ctx)
{
Object protocolId = getBoundColumn().getValue(ctx);

Expand All @@ -69,7 +68,7 @@ protected Pair<ExpProtocol, ActionURL> getExpValue(RenderContext ctx)
url = PageFlowUtil.urlProvider(AssayUrls.class).getAssayRunsURL(c, protocol);
else if (protocol != null)
url = PageFlowUtil.urlProvider(ExperimentUrls.class).getProtocolDetailsURL(protocol);
return protocol == null ? null : new Pair<>(protocol, url);
return protocol == null ? null : new ExpLink<>(protocol, url);
}
}
return null;
Expand Down
5 changes: 2 additions & 3 deletions api/src/org/labkey/api/audit/data/RunColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.labkey.api.exp.api.ExperimentService;
import org.labkey.api.exp.api.ExperimentUrls;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.Pair;
import org.labkey.api.view.ActionURL;

/**
Expand Down Expand Up @@ -55,7 +54,7 @@ protected String extractFromKey3(RenderContext ctx)

@Override
@Nullable
protected Pair<ExpRun, ActionURL> getExpValue(RenderContext ctx)
protected ExpLink<ExpRun> getExpValue(RenderContext ctx)
{
String runLsid = (String) getBoundColumn().getValue(ctx);
if (runLsid != null)
Expand All @@ -77,7 +76,7 @@ protected Pair<ExpRun, ActionURL> getExpValue(RenderContext ctx)
else if (run != null)
url = PageFlowUtil.urlProvider(ExperimentUrls.class).getRunGraphURL(run);

return run == null ? null : new Pair<>(run, url);
return run == null ? null : new ExpLink<>(run, url);
}
}
return null;
Expand Down
7 changes: 3 additions & 4 deletions api/src/org/labkey/api/audit/data/RunGroupColumn.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@
import org.labkey.api.exp.api.ExperimentService;
import org.labkey.api.exp.api.ExperimentUrls;
import org.labkey.api.util.PageFlowUtil;
import org.labkey.api.util.Pair;
import org.labkey.api.view.ActionURL;

/**
* User: klum
* Date: Mar 15, 2012
*/
public class RunGroupColumn extends ExperimentAuditColumn
public class RunGroupColumn extends ExperimentAuditColumn<ExpExperiment>
{
public RunGroupColumn(ColumnInfo col, ColumnInfo containerId, @Nullable ColumnInfo defaultName)
{
Expand All @@ -39,7 +38,7 @@ public RunGroupColumn(ColumnInfo col, ColumnInfo containerId, @Nullable ColumnIn

@Nullable
@Override
protected Pair getExpValue(RenderContext ctx)
protected ExpLink<ExpExperiment> getExpValue(RenderContext ctx)
{
Object rowId = getBoundColumn().getValue(ctx);
if (rowId != null)
Expand All @@ -53,7 +52,7 @@ protected Pair getExpValue(RenderContext ctx)
if (runGroup != null)
url = PageFlowUtil.urlProvider(ExperimentUrls.class).getExperimentDetailsURL(c, runGroup);

return runGroup == null ? null : new Pair<>(runGroup, url);
return runGroup == null ? null : new ExpLink<>(runGroup, url);
}
}
return null;
Expand Down
13 changes: 9 additions & 4 deletions api/src/org/labkey/api/data/SchemaColumnMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.labkey.data.xml.ColumnType;
import org.labkey.data.xml.TableType;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
Expand Down Expand Up @@ -254,13 +255,17 @@ private DbScope.RetryFn<Void> createRetryWrapper(RetrySqlException retry)

private void loadFromMetaData(SchemaTableInfo ti) throws SQLException
{
try (var ignore = DebugInfoDumper.pushThreadDumpContext("SchemaColumnMetaData.loadFromMetaData(" + ti.getSelectName() + ")"))
DbScope scope = ti.getSchema().getScope();

// Hold the thread connection so the three metadata passes share one pool borrow
try (var ignore = DebugInfoDumper.pushThreadDumpContext("SchemaColumnMetaData.loadFromMetaData(" + ti.getSelectName() + ")");
Connection ignored = scope.getConnection())
{
// With the Microsoft JDBC driver we're seeing more deadlocks loading schema metadata so try multiple
// times when possible
ti.getSchema().getScope().executeWithRetryReadOnly(createRetryWrapper((tx) -> loadColumnsFromMetaData(ti)));
ti.getSchema().getScope().executeWithRetryReadOnly(createRetryWrapper((tx) -> loadPkColumns(ti)));
ti.getSchema().getScope().executeWithRetryReadOnly(createRetryWrapper((tx) -> loadIndices(ti)));
scope.executeWithRetryReadOnly(createRetryWrapper((tx) -> loadColumnsFromMetaData(ti)));
scope.executeWithRetryReadOnly(createRetryWrapper((tx) -> loadPkColumns(ti)));
scope.executeWithRetryReadOnly(createRetryWrapper((tx) -> loadIndices(ti)));
}
catch (RuntimeSQLException e)
{
Expand Down
Loading
Loading