org.protempa.backend.dsb.relationaldb.ResultCache Maven / Gradle / Ivy
Show all versions of protempa-dsb-relationaldb Show documentation
/*
* #%L
* Protempa Commons Backend Provider
* %%
* Copyright (C) 2012 - 2013 Emory University
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package org.protempa.backend.dsb.relationaldb;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.arp.javautil.collections.Collections;
import org.eurekaclinical.datastore.DataStore;
import org.protempa.datastore.PropositionStoreCreator;
import org.protempa.datastore.UniqueIdUniqueIdStoreCreator;
import org.protempa.proposition.Proposition;
import org.protempa.proposition.UniqueId;
public class ResultCache {
private Map> inMemoryPatientCache;
private final List>> patientCache;
private Map> tmpInMemoryRefCache;
private int patientCacheNumber;
private DataStore> currentPatientCache;
private Map propIdToEntitySpecNames;
private int indexForAnyAdded;
private Set keyIds;
private Map>>> refCache;
private final PropositionStoreCreator propositionStoreCreator;
private final UniqueIdUniqueIdStoreCreator uniqueIdCreator;
ResultCache() throws IOException {
this.inMemoryPatientCache = new HashMap<>();
this.patientCache = new ArrayList<>();
this.propositionStoreCreator = new PropositionStoreCreator();
this.uniqueIdCreator = new UniqueIdUniqueIdStoreCreator();
this.currentPatientCache = this.propositionStoreCreator.newCacheStore();
this.patientCache.add(this.currentPatientCache);
this.refCache = new HashMap<>();
this.tmpInMemoryRefCache =
new HashMap<>();
this.propIdToEntitySpecNames = new HashMap<>();
this.keyIds = new HashSet<>();
}
public BDBDataSourceResultMap
getPatientCache() {
this.inMemoryPatientCache = null;
this.tmpInMemoryRefCache = null;
return new BDBDataSourceResultMap<>(this.patientCache,
this.refCache, this.propIdToEntitySpecNames, this.keyIds);
}
boolean anyAdded() {
return !this.patientCache.get(indexForAnyAdded).isEmpty();
}
void addReference(UniqueId uid, UniqueId refUid) {
Collections.putList(this.tmpInMemoryRefCache, uid, refUid);
}
void flushReferences(RefResultProcessor
resultProcessor) throws IOException {
DataStore> databaseMap =
this.uniqueIdCreator.newCacheStore();
Collections.putList(this.refCache,
resultProcessor.getEntitySpec().getName(), databaseMap);
String refName =
resultProcessor.getReferenceSpec().getReferenceName();
for (Map.Entry> me :
this.tmpInMemoryRefCache.entrySet()) {
UniqueId key = me.getKey();
List uids = me.getValue();
List refs =
new ArrayList<>(uids.size());
for (UniqueId uid : uids) {
refs.add(new UniqueIdUniqueIdStoreCreator.Reference(refName, uid));
}
databaseMap.put(key, refs);
}
this.tmpInMemoryRefCache.clear();
}
void add(String keyId, P proposition) {
assert keyId != null : "keyId cannot be null";
/*
* We used to intern the keyId here, but that in retrospect was a bad
* idea because there could be millions of them.
*/
Collections.putList(this.inMemoryPatientCache, keyId, proposition);
}
void flush(SQLGenResultProcessor resultProcessor) throws IOException {
String entitySpecName = resultProcessor.getEntitySpec().getName();
assert entitySpecName != null : "entitySpecName cannot be null";
for (Map.Entry> me : this.inMemoryPatientCache.entrySet()) {
List propList = me.getValue();
for (P prop : propList) {
this.propIdToEntitySpecNames.put(prop.getId(), entitySpecName);
}
String keyId = me.getKey();
/**
* After inMemoryPatientCache is cleared, all values will be an
* empty list. Thus, we need to check if the list is not empty, or
* addAll will remove values from the cache, add nothing to them,
* and add them back... The absence of the isEmpty check caused
* massive performance degradation.
*/
if (propList != null && !propList.isEmpty()) {
addAll(keyId, propList);
}
}
for (List
value : this.inMemoryPatientCache.values()) {
value.clear();
}
this.currentPatientCache = this.propositionStoreCreator.newCacheStore();
this.patientCache.add(this.currentPatientCache);
this.patientCacheNumber++;
}
void clearTmp() {
this.indexForAnyAdded = this.patientCacheNumber;
}
void shutdown() {
for (DataStore> ds : this.patientCache) {
ds.shutdown();
}
for (List>> dsl : this.refCache.values()) {
for (DataStore> ds : dsl) {
ds.shutdown();
}
}
}
private void put(String keyId, List propList) {
// first, we add to or update the patients cache
this.currentPatientCache.put(keyId, propList);
this.keyIds.add(keyId);
}
private void addAll(String keyId, List
propositions) {
List
propList = this.currentPatientCache.remove(keyId);
if (propList == null) {
propList = new ArrayList<>();
}
propList.addAll(propositions);
put(keyId, propList);
}
}