Lazy load binaries for reduced memory usage

This commit is contained in:
Grahame Grieve 2025-01-06 10:56:43 +11:00
parent d11b358e39
commit 12cfe341fc
2 changed files with 67 additions and 12 deletions

View File

@ -57,6 +57,7 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.TerminologyServiceException; import org.hl7.fhir.exceptions.TerminologyServiceException;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.BaseWorkerContext.IByteProvider;
import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy; import org.hl7.fhir.r5.context.CanonicalResourceManager.CanonicalResourceProxy;
import org.hl7.fhir.r5.context.ILoggingService.LogCategory; import org.hl7.fhir.r5.context.ILoggingService.LogCategory;
import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails; import org.hl7.fhir.r5.context.IWorkerContext.ITerminologyOperationDetails;
@ -141,6 +142,7 @@ import org.hl7.fhir.r5.utils.UserDataNames;
import org.hl7.fhir.r5.utils.client.EFhirClientException; import org.hl7.fhir.r5.utils.client.EFhirClientException;
import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier; import org.hl7.fhir.r5.utils.validation.ValidationContextCarrier;
import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.ToolingClientLogger; import org.hl7.fhir.utilities.ToolingClientLogger;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
@ -148,6 +150,7 @@ import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
import org.hl7.fhir.utilities.i18n.I18nBase; import org.hl7.fhir.utilities.i18n.I18nBase;
import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
@ -158,6 +161,58 @@ import javax.annotation.Nonnull;
public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext { public abstract class BaseWorkerContext extends I18nBase implements IWorkerContext {
public interface IByteProvider {
byte[] bytes() throws IOException;
}
public class BytesProvider implements IByteProvider {
private byte[] bytes;
protected BytesProvider(byte[] bytes) {
super();
this.bytes = bytes;
}
@Override
public byte[] bytes() throws IOException {
return bytes;
}
}
public class BytesFromPackageProvider implements IByteProvider {
private NpmPackage pi;
private String name;
public BytesFromPackageProvider(NpmPackage pi, String name) {
this.pi = pi;
this.name = name;
}
@Override
public byte[] bytes() throws IOException {
return TextFile.streamToBytes(pi.load("other", name));
}
}
public class BytesFromFileProvider implements IByteProvider {
private String name;
public BytesFromFileProvider(String name) {
this.name = name;
}
@Override
public byte[] bytes() throws IOException {
return TextFile.streamToBytes(ManagedFileAccess.inStream(name));
}
}
class OIDSource { class OIDSource {
private String folder; private String folder;
private Connection db; private Connection db;
@ -265,7 +320,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
private UcumService ucumService; private UcumService ucumService;
protected Map<String, byte[]> binaries = new HashMap<String, byte[]>(); protected Map<String, IByteProvider> binaries = new HashMap<String, IByteProvider>();
protected Map<String, Set<OIDDefinition>> oidCacheManual = new HashMap<>(); protected Map<String, Set<OIDDefinition>> oidCacheManual = new HashMap<>();
protected List<OIDSource> oidSources = new ArrayList<>(); protected List<OIDSource> oidSources = new ArrayList<>();
@ -3137,7 +3192,12 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
@Override @Override
public byte[] getBinaryForKey(String binaryKey) { public byte[] getBinaryForKey(String binaryKey) {
return binaries.get(binaryKey); IByteProvider bp = binaries.get(binaryKey);
try {
return bp == null ? null : bp.bytes();
} catch (Exception e) {
throw new FHIRException(e);
}
} }
public void finishLoading(boolean genSnapshots) { public void finishLoading(boolean genSnapshots) {

View File

@ -352,7 +352,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
else if (name.equals("version.info")) else if (name.equals("version.info"))
readVersionInfo(stream); readVersionInfo(stream);
else else
loadBytes(name, stream); binaries.put(name, new BytesProvider(TextFile.streamToBytes(stream)));
} }
public void connectToTSServer(ITerminologyClientFactory factory, ITerminologyClient client, boolean useEcosystem) { public void connectToTSServer(ITerminologyClientFactory factory, ITerminologyClient client, boolean useEcosystem) {
@ -572,7 +572,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
} }
} }
for (String s : pi.list("other")) { for (String s : pi.list("other")) {
binaries.put(s, TextFile.streamToBytes(pi.load("other", s))); binaries.put(s, new BytesFromPackageProvider(pi, s));
} }
if (version == null) { if (version == null) {
version = pi.version(); version = pi.version();
@ -606,7 +606,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
private void readVersionInfo(InputStream stream) throws IOException, DefinitionException { private void readVersionInfo(InputStream stream) throws IOException, DefinitionException {
byte[] bytes = IOUtils.toByteArray(stream); byte[] bytes = IOUtils.toByteArray(stream);
binaries.put("version.info", bytes); binaries.put("version.info", new BytesProvider(bytes));
String[] vi = new String(bytes).split("\\r?\\n"); String[] vi = new String(bytes).split("\\r?\\n");
for (String s : vi) { for (String s : vi) {
@ -624,11 +624,6 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
} }
} }
private void loadBytes(String name, InputStream stream) throws IOException {
byte[] bytes = IOUtils.toByteArray(stream);
binaries.put(name, bytes);
}
@Override @Override
public IResourceValidator newValidator() throws FHIRException { public IResourceValidator newValidator() throws FHIRException {
if (validatorFactory == null) if (validatorFactory == null)
@ -662,13 +657,13 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
public void loadBinariesFromFolder(String folder) throws IOException { public void loadBinariesFromFolder(String folder) throws IOException {
for (String n : ManagedFileAccess.file(folder).list()) { for (String n : ManagedFileAccess.file(folder).list()) {
loadBytes(n, ManagedFileAccess.inStream(Utilities.path(folder, n))); binaries.put(n, new BytesFromFileProvider(Utilities.path(folder, n)));
} }
} }
public void loadBinariesFromFolder(NpmPackage pi) throws IOException { public void loadBinariesFromFolder(NpmPackage pi) throws IOException {
for (String n : pi.list("other")) { for (String n : pi.list("other")) {
loadBytes(n, pi.load("other", n)); binaries.put(n, new BytesFromPackageProvider(pi, n));
} }
} }