Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 45 additions & 3 deletions packages/composer-runtime/lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ class Context {
LOG.exit(method);
}

/**
* Get a compiled script bundle from the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
* @return {CompiledScriptBundle} The cached compiled script bundle, or null if
* there is no entry in the cache for the specified business network definition.
*/
static getCachedCompiledScriptBundle(businessNetworkHash) {
const method = 'getCachedCompiledScriptBundle';
LOG.entry(method, businessNetworkHash);
const result = compiledScriptBundleCache.get(businessNetworkHash);
LOG.exit(method, result);
return result;
}

/**
* Store a compiled script bundle in the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
Expand All @@ -67,6 +81,20 @@ class Context {
LOG.exit(method);
}

/**
* Get a compiled query bundle from the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
* @return {CompiledQueryBundle} The cached compiled query bundle, or null if
* there is no entry in the cache for the specified business network definition.
*/
static getCachedCompiledQueryBundle(businessNetworkHash) {
const method = 'getCachedCompiledQueryBundle';
LOG.entry(method, businessNetworkHash);
const result = compiledQueryBundleCache.get(businessNetworkHash);
LOG.exit(method, result);
return result;
}

/**
* Store a compiled query bundle in the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
Expand All @@ -79,6 +107,20 @@ class Context {
LOG.exit(method);
}

/**
* Get a compiled ACL bundle from the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
* @return {CompiledAclBundle} The cached compiled ACL bundle, or null if
* there is no entry in the cache for the specified business network definition.
*/
static getCachedCompiledAclBundle(businessNetworkHash) {
const method = 'getCachedCompiledAclBundle';
LOG.entry(method, businessNetworkHash);
const result = compiledAclBundleCache.get(businessNetworkHash);
LOG.exit(method, result);
return result;
}

/**
* Store a compiled ACL bundle in the cache.
* @param {string} businessNetworkHash The hash of the business network definition.
Expand Down Expand Up @@ -197,7 +239,7 @@ class Context {
const method = 'loadCompiledScriptBundle';
LOG.entry(method);
LOG.debug(method, 'Looking in cache for compiled script bundle', businessNetworkRecord.hash);
let compiledScriptBundle = compiledScriptBundleCache.get(businessNetworkRecord.hash);
let compiledScriptBundle = Context.getCachedCompiledScriptBundle(businessNetworkRecord.hash);
if (compiledScriptBundle) {
LOG.debug(method, 'Compiled script bundle is in cache');
return Promise.resolve(compiledScriptBundle);
Expand Down Expand Up @@ -227,7 +269,7 @@ class Context {
const method = 'loadCompiledQueryBundle';
LOG.entry(method);
LOG.debug(method, 'Looking in cache for compiled query bundle', businessNetworkRecord.hash);
let compiledQueryBundle = compiledQueryBundleCache.get(businessNetworkRecord.hash);
let compiledQueryBundle = Context.getCachedCompiledQueryBundle(businessNetworkRecord.hash);
if (compiledQueryBundle) {
LOG.debug(method, 'Compiled query bundle is in cache');
return Promise.resolve(compiledQueryBundle);
Expand Down Expand Up @@ -257,7 +299,7 @@ class Context {
const method = 'loadCompiledAclBundle';
LOG.entry(method);
LOG.debug(method, 'Looking in cache for compiled ACL bundle', businessNetworkRecord.hash);
let compiledAclBundle = compiledAclBundleCache.get(businessNetworkRecord.hash);
let compiledAclBundle = Context.getCachedCompiledAclBundle(businessNetworkRecord.hash);
if (compiledAclBundle) {
LOG.debug(method, 'Compiled ACL bundle is in cache');
return Promise.resolve(compiledAclBundle);
Expand Down
27 changes: 18 additions & 9 deletions packages/composer-runtime/lib/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,28 @@ class Engine {
Context.cacheBusinessNetwork(businessNetworkHash, businessNetworkDefinition);

// Cache the compiled script bundle.
compiledScriptBundle = context.getScriptCompiler().compile(businessNetworkDefinition.getScriptManager());
LOG.debug(method, 'Loaded compiled script bundle, storing in cache');
Context.cacheCompiledScriptBundle(businessNetworkHash, compiledScriptBundle);
compiledScriptBundle = Context.getCachedCompiledScriptBundle(businessNetworkHash);
if (!compiledScriptBundle) {
compiledScriptBundle = context.getScriptCompiler().compile(businessNetworkDefinition.getScriptManager());
LOG.debug(method, 'Loaded compiled script bundle, storing in cache');
Context.cacheCompiledScriptBundle(businessNetworkHash, compiledScriptBundle);
}

// Cache the compiled query bundle.
compiledQueryBundle = context.getQueryCompiler().compile(businessNetworkDefinition.getQueryManager());
LOG.debug(method, 'Loaded compiled query bundle, storing in cache');
Context.cacheCompiledQueryBundle(businessNetworkHash, compiledQueryBundle);
compiledQueryBundle = Context.getCachedCompiledQueryBundle(businessNetworkHash);
if (!compiledQueryBundle) {
compiledQueryBundle = context.getQueryCompiler().compile(businessNetworkDefinition.getQueryManager());
LOG.debug(method, 'Loaded compiled query bundle, storing in cache');
Context.cacheCompiledQueryBundle(businessNetworkHash, compiledQueryBundle);
}

// Cache the compiled ACL bundle.
compiledAclBundle = context.getAclCompiler().compile(businessNetworkDefinition.getAclManager(), businessNetworkDefinition.getScriptManager());
LOG.debug(method, 'Loaded compiled ACL bundle, storing in cache');
Context.cacheCompiledAclBundle(businessNetworkHash, compiledAclBundle);
compiledAclBundle = Context.getCachedCompiledAclBundle(businessNetworkHash);
if (!compiledAclBundle) {
compiledAclBundle = context.getAclCompiler().compile(businessNetworkDefinition.getAclManager(), businessNetworkDefinition.getScriptManager());
LOG.debug(method, 'Loaded compiled ACL bundle, storing in cache');
Context.cacheCompiledAclBundle(businessNetworkHash, compiledAclBundle);
}

// Get the sysdata collection where the business network definition is stored.
LOG.debug(method, 'Loaded business network definition, storing in $sysdata collection');
Expand Down
102 changes: 102 additions & 0 deletions packages/composer-runtime/test/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,108 @@ describe('Engine', () => {
});
});

it('should reuse the cached compiled script bundle', () => {
let sysdata = sinon.createStubInstance(DataCollection);
let sysregistries = sinon.createStubInstance(DataCollection);
mockDataService.ensureCollection.withArgs('$sysdata').resolves(sysdata);
let mockBusinessNetworkDefinition = sinon.createStubInstance(BusinessNetworkDefinition);
let mockScriptManager = sinon.createStubInstance(ScriptManager);
mockBusinessNetworkDefinition.getScriptManager.returns(mockScriptManager);
mockBusinessNetworkDefinition.getIdentifier.returns('test');
sandbox.stub(BusinessNetworkDefinition, 'fromArchive').resolves(mockBusinessNetworkDefinition);
let mockScriptCompiler = sinon.createStubInstance(ScriptCompiler);
let mockCompiledScriptBundle = sinon.createStubInstance(CompiledScriptBundle);
mockScriptCompiler.compile.throws(new Error('should not be called'));
mockContext.getScriptCompiler.returns(mockScriptCompiler);
Context.cacheCompiledScriptBundle('dc9c1c09907c36f5379d615ae61c02b46ba254d92edb77cb63bdcc5247ccd01c', mockCompiledScriptBundle);
let mockQueryCompiler = sinon.createStubInstance(QueryCompiler);
let mockCompiledQueryBundle = sinon.createStubInstance(CompiledQueryBundle);
mockQueryCompiler.compile.returns(mockCompiledQueryBundle);
mockContext.getQueryCompiler.returns(mockQueryCompiler);
let mockAclCompiler = sinon.createStubInstance(AclCompiler);
let mockCompiledAclBundle = sinon.createStubInstance(CompiledAclBundle);
mockAclCompiler.compile.returns(mockCompiledAclBundle);
mockContext.getAclCompiler.returns(mockAclCompiler);
sysdata.add.withArgs('businessnetwork', sinon.match.any).resolves();
mockDataService.ensureCollection.withArgs('$sysregistries').resolves(sysregistries);
mockRegistryManager.ensure.withArgs('Transaction', 'default', 'Default Transaction Registry').resolves();
sandbox.stub(Context, 'cacheBusinessNetwork');
sandbox.stub(Context, 'cacheCompiledScriptBundle');
mockRegistryManager.createDefaults.resolves();
return engine.init(mockContext, 'init', ['aGVsbG8gd29ybGQ=','{}'])
.then(() => {
sinon.assert.notCalled(Context.cacheCompiledScriptBundle);
});
});

it('should reuse the cached compiled query bundle', () => {
let sysdata = sinon.createStubInstance(DataCollection);
let sysregistries = sinon.createStubInstance(DataCollection);
mockDataService.ensureCollection.withArgs('$sysdata').resolves(sysdata);
let mockBusinessNetworkDefinition = sinon.createStubInstance(BusinessNetworkDefinition);
let mockScriptManager = sinon.createStubInstance(ScriptManager);
mockBusinessNetworkDefinition.getScriptManager.returns(mockScriptManager);
mockBusinessNetworkDefinition.getIdentifier.returns('test');
sandbox.stub(BusinessNetworkDefinition, 'fromArchive').resolves(mockBusinessNetworkDefinition);
let mockScriptCompiler = sinon.createStubInstance(ScriptCompiler);
let mockCompiledScriptBundle = sinon.createStubInstance(CompiledScriptBundle);
mockScriptCompiler.compile.returns(mockCompiledScriptBundle);
mockContext.getScriptCompiler.returns(mockScriptCompiler);
let mockQueryCompiler = sinon.createStubInstance(QueryCompiler);
let mockCompiledQueryBundle = sinon.createStubInstance(CompiledQueryBundle);
mockQueryCompiler.compile.throws(new Error('should not be called'));
mockContext.getQueryCompiler.returns(mockQueryCompiler);
Context.cacheCompiledQueryBundle('dc9c1c09907c36f5379d615ae61c02b46ba254d92edb77cb63bdcc5247ccd01c', mockCompiledQueryBundle);
let mockAclCompiler = sinon.createStubInstance(AclCompiler);
let mockCompiledAclBundle = sinon.createStubInstance(CompiledAclBundle);
mockAclCompiler.compile.returns(mockCompiledAclBundle);
mockContext.getAclCompiler.returns(mockAclCompiler);
sysdata.add.withArgs('businessnetwork', sinon.match.any).resolves();
mockDataService.ensureCollection.withArgs('$sysregistries').resolves(sysregistries);
mockRegistryManager.ensure.withArgs('Transaction', 'default', 'Default Transaction Registry').resolves();
sandbox.stub(Context, 'cacheBusinessNetwork');
sandbox.stub(Context, 'cacheCompiledQueryBundle');
mockRegistryManager.createDefaults.resolves();
return engine.init(mockContext, 'init', ['aGVsbG8gd29ybGQ=','{}'])
.then(() => {
sinon.assert.notCalled(Context.cacheCompiledQueryBundle);
});
});

it('should reuse the cached compiled ACL bundle', () => {
let sysdata = sinon.createStubInstance(DataCollection);
let sysregistries = sinon.createStubInstance(DataCollection);
mockDataService.ensureCollection.withArgs('$sysdata').resolves(sysdata);
let mockBusinessNetworkDefinition = sinon.createStubInstance(BusinessNetworkDefinition);
let mockScriptManager = sinon.createStubInstance(ScriptManager);
mockBusinessNetworkDefinition.getScriptManager.returns(mockScriptManager);
mockBusinessNetworkDefinition.getIdentifier.returns('test');
sandbox.stub(BusinessNetworkDefinition, 'fromArchive').resolves(mockBusinessNetworkDefinition);
let mockScriptCompiler = sinon.createStubInstance(ScriptCompiler);
let mockCompiledScriptBundle = sinon.createStubInstance(CompiledScriptBundle);
mockScriptCompiler.compile.returns(mockCompiledScriptBundle);
mockContext.getScriptCompiler.returns(mockScriptCompiler);
let mockQueryCompiler = sinon.createStubInstance(QueryCompiler);
let mockCompiledQueryBundle = sinon.createStubInstance(CompiledQueryBundle);
mockQueryCompiler.compile.returns(mockCompiledQueryBundle);
mockContext.getQueryCompiler.returns(mockQueryCompiler);
let mockAclCompiler = sinon.createStubInstance(AclCompiler);
let mockCompiledAclBundle = sinon.createStubInstance(CompiledAclBundle);
mockAclCompiler.compile.throws(new Error('should not be called'));
mockContext.getAclCompiler.returns(mockAclCompiler);
Context.cacheCompiledAclBundle('dc9c1c09907c36f5379d615ae61c02b46ba254d92edb77cb63bdcc5247ccd01c', mockCompiledAclBundle);
sysdata.add.withArgs('businessnetwork', sinon.match.any).resolves();
mockDataService.ensureCollection.withArgs('$sysregistries').resolves(sysregistries);
mockRegistryManager.ensure.withArgs('Transaction', 'default', 'Default Transaction Registry').resolves();
sandbox.stub(Context, 'cacheBusinessNetwork');
sandbox.stub(Context, 'cacheCompiledAclBundle');
mockRegistryManager.createDefaults.resolves();
return engine.init(mockContext, 'init', ['aGVsbG8gd29ybGQ=','{}'])
.then(() => {
sinon.assert.notCalled(Context.cacheCompiledAclBundle);
});
});

it('should throw if an error occurs', () => {
let mockDataCollection = sinon.createStubInstance(DataCollection);
mockDataService.getCollection.rejects();
Expand Down