Skip to content

Commit aa8eba5

Browse files
committed
Merge remote-tracking branch 'origin/develop' into fb_miscAmountsAndUnits
# Conflicts: # experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java
2 parents 30cbf6c + 914912e commit aa8eba5

7 files changed

Lines changed: 48 additions & 39 deletions

File tree

api/src/org/labkey/api/cache/BlockingCache.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,12 @@ public V get(@NotNull K key, @Nullable Object argument, CacheLoader<K, V> loader
9696
{
9797
Wrapper<V> w;
9898

99+
if (null == loader)
100+
loader = _loader;
101+
99102
try (var ignored = DebugInfoDumper.pushThreadDumpContext(this.getClass().getSimpleName() + ".get(" + key + ")"))
100103
{
101-
synchronized(_cache)
104+
synchronized (loader == null ? _cache : loader.getSyncObject(_cache))
102105
{
103106
w = _cache.get(key);
104107
if (null == w)
@@ -153,9 +156,6 @@ public V get(@NotNull K key, @Nullable Object argument, CacheLoader<K, V> loader
153156

154157
try
155158
{
156-
if (null == loader)
157-
loader = _loader;
158-
159159
if (null == loader)
160160
throw new IllegalStateException("cache loader was not provided");
161161

api/src/org/labkey/api/cache/Cache.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,14 @@ public interface Cache<K, V>
4242
*/
4343
int removeUsingFilter(Predicate<K> filter);
4444

45-
class StringPrefixFilter implements Predicate<String>
46-
{
47-
private final String _prefix;
48-
49-
public StringPrefixFilter(String prefix)
50-
{
51-
_prefix = prefix;
52-
}
53-
54-
@Override
55-
public boolean test(String s)
45+
record StringPrefixFilter(String prefix) implements Predicate<String>
5646
{
57-
return s.startsWith(_prefix);
47+
@Override
48+
public boolean test(String s)
49+
{
50+
return s.startsWith(prefix);
51+
}
5852
}
59-
}
6053

6154
Set<K> getKeys();
6255

api/src/org/labkey/api/cache/CacheLoader.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,13 @@
2525
public interface CacheLoader<K, V>
2626
{
2727
V load(@NotNull K key, @Nullable Object argument);
28+
29+
/**
30+
* Returns an object that can be used to synchronize access to the cache. Typically, the cache itself but it's
31+
* OK to swap with another lock object when running inside of a transaction to reduce the likelihood of deadlocks.
32+
*/
33+
default Object getSyncObject(Cache<?, ?> cache)
34+
{
35+
return cache;
36+
}
2837
}

api/src/org/labkey/api/data/TransactionCache.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,23 @@ public V get(@NotNull K key)
6969
return get(key, null, null);
7070
}
7171

72+
73+
/** A dummy loader that never fetches a value. Lets us see if the shared cache already has a value for this key. */
74+
private final CacheLoader<K, V> _nonLoader = new CacheLoader<K, V>()
75+
{
76+
@Override
77+
public V load(@NotNull K key, @Nullable Object argument)
78+
{
79+
throw new MissingCacheEntryException();
80+
}
81+
82+
@Override
83+
public Object getSyncObject(Cache<?, ?> cache)
84+
{
85+
return TransactionCache.this;
86+
}
87+
};
88+
7289
@Override
7390
public V get(@NotNull K key, Object arg, @Nullable CacheLoader<K, V> loader)
7491
{
@@ -85,9 +102,7 @@ else if (null == v && !_hasBeenCleared)
85102
try
86103
{
87104
// Entry has not been modified in the private cache, so read through to shared cache
88-
v = _sharedCache.get(key, null, (key1, argument) -> {
89-
throw new MissingCacheEntryException();
90-
});
105+
v = _sharedCache.get(key, null, _nonLoader);
91106
// Shared cache has an entry for this key, so return it and don't invoke the loader
92107
if (null == v)
93108
v = NULL_MARKER; // Cached miss in shared cache; use null marker to skip loading. Issue 47234

api/src/org/labkey/api/query/UserSchema.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,16 +273,15 @@ public Object _getTableOrQuery(String name, ContainerFilter cf, boolean includeE
273273
if (!canReadSchema())
274274
return null; // See #21014
275275

276-
TableInfo table = null;
276+
TableInfo table;
277277
String cacheKey = cacheKey(name, cf, includeExtraMetadata, forWrite);
278278
if (null != cacheKey)
279279
{
280280
table = tableInfoCache.get(cacheKey);
281281
if (null != table)
282282
return table;
283283
}
284-
if (null == table)
285-
table = createTable(name, cf, includeExtraMetadata);
284+
table = createTable(name, cf, includeExtraMetadata);
286285
Object torq;
287286

288287
if (table != null)

experiment/src/org/labkey/experiment/api/ExpSampleTypeImpl.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,8 +931,6 @@ public void save(User user)
931931
}
932932
}
933933

934-
// NOTE cacheMaterialSource() of course calls transactioncache.put(), which does not alter the shared cache! (BUG?)
935-
// Just call uncache(), and let normal cache loading do its thing
936934
SampleTypeServiceImpl.get().clearMaterialSourceCache(getContainer());
937935
}
938936

experiment/src/org/labkey/experiment/api/SampleTypeServiceImpl.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.labkey.api.data.ContainerFilter;
4646
import org.labkey.api.data.ContainerManager;
4747
import org.labkey.api.data.ConversionExceptionWithMessage;
48+
import org.labkey.api.data.DatabaseCache;
4849
import org.labkey.api.data.DbSchema;
4950
import org.labkey.api.data.DbScope;
5051
import org.labkey.api.data.DbSequence;
@@ -202,10 +203,11 @@ public static SampleTypeServiceImpl get()
202203

203204
private static final Logger LOG = LogHelper.getLogger(SampleTypeServiceImpl.class, "Info about sample type operations");
204205

205-
// SampleType -> Container cache
206+
/** SampleType LSID -> Container cache */
206207
private final Cache<String, String> sampleTypeCache = CacheManager.getStringKeyCache(CacheManager.UNLIMITED, CacheManager.DAY, "SampleType to container");
207208

208-
private final Cache<String, SortedSet<MaterialSource>> materialSourceCache = CacheManager.getBlockingStringKeyCache(CacheManager.UNLIMITED, CacheManager.DAY, "Material sources", (container, argument) ->
209+
/** ContainerId -> MaterialSources */
210+
private final Cache<String, SortedSet<MaterialSource>> materialSourceCache = DatabaseCache.get(ExperimentServiceImpl.get().getSchema().getScope(), CacheManager.UNLIMITED, CacheManager.DAY, "Material sources", (container, argument) ->
209211
{
210212
Container c = ContainerManager.getForId(container);
211213
if (c == null)
@@ -215,7 +217,6 @@ public static SampleTypeServiceImpl get()
215217
return Collections.unmodifiableSortedSet(new TreeSet<>(new TableSelector(getTinfoMaterialSource(), filter, null).getCollection(MaterialSource.class)));
216218
});
217219

218-
219220
Cache<String, SortedSet<MaterialSource>> getMaterialSourceCache()
220221
{
221222
return materialSourceCache;
@@ -954,9 +955,7 @@ public ExpSampleTypeImpl createSampleType(Container c, User u, String name, Stri
954955
else
955956
ExperimentService.get().ensureDataTypeContainerExclusionsNonAdmin(ExperimentService.DataTypeForExclusion.DashboardSampleType, st.getRowId(), c, u);
956957
transaction.addCommitTask(() -> clearMaterialSourceCache(c), DbScope.CommitTaskOption.IMMEDIATE, POSTCOMMIT, POSTROLLBACK);
957-
transaction.addCommitTask(() -> {
958-
indexSampleType(SampleTypeService.get().getSampleType(domain.getTypeURI()), SearchService.get().defaultTask().getQueue(c, SearchService.PRIORITY.modified));
959-
}, POSTCOMMIT);
958+
transaction.addCommitTask(() -> indexSampleType(SampleTypeService.get().getSampleType(domain.getTypeURI()), SearchService.get().defaultTask().getQueue(c, SearchService.PRIORITY.modified)), POSTCOMMIT);
960959

961960
return st;
962961
}
@@ -1012,8 +1011,7 @@ public long next(Date date)
10121011
public DbSequence getDbSequence(Date date)
10131012
{
10141013
Pair<String,Integer> seqName = getSequenceName(date);
1015-
final DbSequence seq = DbSequenceManager.getPreallocatingSequence(ContainerManager.getRoot(), seqName.first, seqName.second, 100);
1016-
return seq;
1014+
return DbSequenceManager.getPreallocatingSequence(ContainerManager.getRoot(), seqName.first, seqName.second, 100);
10171015
}
10181016
}
10191017

@@ -1083,7 +1081,7 @@ public ValidationException updateSampleType(GWTDomain<? extends GWTPropertyDescr
10831081
validateSampleTypeName(container, user, newName, oldSampleTypeName.equalsIgnoreCase(newName));
10841082
hasNameChange = true;
10851083
st.setName(newName);
1086-
changeDetails.append("The name of the sample type '" + oldSampleTypeName + "' was changed to '" + newName + "'.");
1084+
changeDetails.append("The name of the sample type '").append(oldSampleTypeName).append("' was changed to '").append(newName).append("'.");
10871085
}
10881086

10891087
String newDescription = StringUtils.trimToNull(update.getDescription());
@@ -1595,7 +1593,7 @@ private AliquotAvailableAmountUnit computeAliquotTotalAmounts(List<AliquotAmount
15951593
return null;
15961594

15971595
Unit totalUnit = null;
1598-
String totalUnitsStr = null;
1596+
String totalUnitsStr;
15991597
if (!StringUtils.isEmpty(sampleTypeUnitsStr))
16001598
totalUnitsStr = sampleTypeUnitsStr;
16011599
else if (!StringUtils.isEmpty(sampleItemUnitsStr))
@@ -1915,9 +1913,7 @@ public Map<String, Integer> moveSamples(Collection<? extends ExpMaterial> sample
19151913
if (inventoryService != null)
19161914
{
19171915
Map<String, Integer> inventoryCounts = inventoryService.moveSamples(sampleIds, targetContainer, user);
1918-
inventoryCounts.forEach((key, count) -> {
1919-
updateCounts.compute(key, (k, c) -> c == null ? count : c + count);
1920-
});
1916+
inventoryCounts.forEach((key, count) -> updateCounts.compute(key, (k, c) -> c == null ? count : c + count));
19211917
}
19221918

19231919
// create summary audit entries for the source and target containers
@@ -2264,7 +2260,6 @@ private void deleteSampleCounterSequence(Container container, boolean isRootOnly
22642260
Container seqContainer = container.getProject();
22652261
DbSequenceManager.delete(seqContainer, seqName);
22662262
DbSequenceManager.invalidatePreallocatingSequence(container, seqName, 0);
2267-
return;
22682263
}
22692264

22702265
@Override

0 commit comments

Comments
 (0)