Skip to content

Commit 6bda940

Browse files
author
Tom Fili
authored
Merge pull request #7848 from AnalyticalGraphicsInc/bing-usage
Reduce Bing Maps transactions and ion Bing sessions
2 parents a9c31c7 + c16f559 commit 6bda940

5 files changed

+127
-9
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Change Log
77
* Added syntax to delete data from existing properties via CZML. [#7818](https://github.com/AnalyticalGraphicsInc/cesium/pull/7818)
88
* Added `checkerboard` material to CZML. [#7845](https://github.com/AnalyticalGraphicsInc/cesium/pull/7845)
99
* `BingMapsImageryProvider` now uses `DiscardEmptyTileImagePolicy` by default to detect missing tiles as zero-length responses instead of inspecting pixel values. [#7810](https://github.com/AnalyticalGraphicsInc/cesium/pull/7810)
10+
* Reduce the number of Bing transactions and ion Bing sessions used when destroying and recreating the same imagery layer to 1. [#7848](https://github.com/AnalyticalGraphicsInc/cesium/pull/7848)
1011

1112
##### Fixes :wrench:
1213
* Fixed an edge case where Cesium would provide ion access token credentials to non-ion servers if the actual asset entrypoint was being hosted by ion. [#7839](https://github.com/AnalyticalGraphicsInc/cesium/pull/7839)

Source/Scene/BingMapsImageryProvider.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,14 @@ define([
174174
for (var attributionIndex = 0, attributionLength = attributionList.length; attributionIndex < attributionLength; ++attributionIndex) {
175175
var attribution = attributionList[attributionIndex];
176176

177-
attribution.credit = new Credit(attribution.attribution);
177+
if (attribution.credit instanceof Credit) {
178+
// If attribution.credit has already been created
179+
// then we are using a cached value, which means
180+
// none of the remaining processing needs to be done.
181+
break;
182+
}
178183

184+
attribution.credit = new Credit(attribution.attribution);
179185
var coverageAreas = attribution.coverageAreas;
180186

181187
for (var areaIndex = 0, areaLength = attribution.coverageAreas.length; areaIndex < areaLength; ++areaIndex) {
@@ -200,12 +206,19 @@ define([
200206
that._readyPromise.reject(new RuntimeError(message));
201207
}
202208

209+
var cacheKey = metadataResource.url;
203210
function requestMetadata() {
204-
var metadata = metadataResource.fetchJsonp('jsonp');
205-
when(metadata, metadataSuccess, metadataFailure);
211+
var promise = metadataResource.fetchJsonp('jsonp');
212+
BingMapsImageryProvider._metadataCache[cacheKey] = promise;
213+
promise.then(metadataSuccess).otherwise(metadataFailure);
206214
}
207215

208-
requestMetadata();
216+
var promise = BingMapsImageryProvider._metadataCache[cacheKey];
217+
if (defined(promise)) {
218+
promise.then(metadataSuccess).otherwise(metadataFailure);
219+
} else {
220+
requestMetadata();
221+
}
209222
}
210223

211224
defineProperties(BingMapsImageryProvider.prototype, {
@@ -697,5 +710,8 @@ define([
697710
return result;
698711
}
699712

713+
// Exposed for testing
714+
BingMapsImageryProvider._metadataCache = {};
715+
700716
return BingMapsImageryProvider;
701717
});

Source/Scene/IonImageryProvider.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ define([
7777
function IonImageryProvider(options) {
7878
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
7979

80+
var assetId = options.assetId;
8081
//>>includeStart('debug', pragmas.debug);
81-
Check.typeOf.number('options.assetId', options.assetId);
82+
Check.typeOf.number('options.assetId', assetId);
8283
//>>includeEnd('debug');
8384

84-
var endpointResource = IonResource._createEndpointResource(options.assetId, options);
85-
8685
/**
8786
* The default alpha blending value of this provider, with 0.0 representing fully transparent and
8887
* 1.0 representing fully opaque.
@@ -156,10 +155,23 @@ define([
156155
this._errorEvent = new Event();
157156

158157
var that = this;
159-
this._readyPromise = endpointResource.fetchJson()
158+
var endpointResource = IonResource._createEndpointResource(assetId, options);
159+
160+
// A simple cache to avoid making repeated requests to ion for endpoints we've
161+
// already retrieved. This exists mainly to support Bing caching to reduce
162+
// world imagery sessions, but provides a small boost of performance in general
163+
// if constantly reloading assets
164+
var cacheKey = options.assetId.toString() + options.accessToken + options.server;
165+
var promise = IonImageryProvider._endpointCache[cacheKey];
166+
if (!defined(promise)) {
167+
promise = endpointResource.fetchJson();
168+
IonImageryProvider._endpointCache[cacheKey] = promise;
169+
}
170+
171+
this._readyPromise = promise
160172
.then(function(endpoint) {
161173
if (endpoint.type !== 'IMAGERY') {
162-
return when.reject(new RuntimeError('Cesium ion asset ' + options.assetId + ' is not an imagery asset.'));
174+
return when.reject(new RuntimeError('Cesium ion asset ' + assetId + ' is not an imagery asset.'));
163175
}
164176

165177
var imageryProvider;
@@ -485,5 +497,8 @@ define([
485497
return this._imageryProvider.pickFeatures(x, y, level, longitude, latitude);
486498
};
487499

500+
//exposed for testing
501+
IonImageryProvider._endpointCache = {};
502+
488503
return IonImageryProvider;
489504
});

Specs/Scene/BingMapsImageryProviderSpec.js

+51
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ defineSuite([
4646

4747
beforeEach(function() {
4848
RequestScheduler.clearForSpecs();
49+
BingMapsImageryProvider._metadataCache = {};
4950
});
5051

5152
afterEach(function() {
@@ -247,6 +248,56 @@ defineSuite([
247248
});
248249
});
249250

251+
it('Uses cached metadata result', function() {
252+
var url = 'http://fake.fake.invalid';
253+
var mapStyle = BingMapsStyle.ROAD;
254+
255+
installFakeMetadataRequest(url, mapStyle);
256+
installFakeImageRequest();
257+
var provider = new BingMapsImageryProvider({
258+
url : url,
259+
mapStyle : mapStyle
260+
});
261+
var provider2;
262+
var provider3;
263+
264+
return provider.readyPromise
265+
.then(function(result) {
266+
expect(result).toBe(true);
267+
expect(provider.ready).toBe(true);
268+
269+
installFakeMetadataRequest(url, mapStyle);
270+
installFakeImageRequest();
271+
provider2 = new BingMapsImageryProvider({
272+
url: url,
273+
mapStyle: mapStyle
274+
});
275+
return provider2.readyPromise;
276+
})
277+
.then(function(result) {
278+
expect(result).toBe(true);
279+
expect(provider2.ready).toBe(true);
280+
281+
//These are the same instance only if the cache has been used
282+
expect(provider._attributionList).toBe(provider2._attributionList);
283+
284+
installFakeMetadataRequest(url, BingMapsStyle.AERIAL);
285+
installFakeImageRequest();
286+
provider3 = new BingMapsImageryProvider({
287+
url: url,
288+
mapStyle: BingMapsStyle.AERIAL
289+
});
290+
return provider3.readyPromise;
291+
})
292+
.then(function(result) {
293+
expect(result).toBe(true);
294+
expect(provider3.ready).toBe(true);
295+
296+
// Because the road is different, a non-cached request should have happened
297+
expect(provider3._attributionList).not.toBe(provider._attributionList);
298+
});
299+
});
300+
250301
it('resolves readyPromise with a path', function() {
251302
var url = 'http://fake.fake.invalid/some/subdirectory';
252303
var mapStyle = BingMapsStyle.ROAD;

Specs/Scene/IonImageryProviderSpec.js

+35
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ defineSuite([
5959

6060
beforeEach(function() {
6161
RequestScheduler.clearForSpecs();
62+
IonImageryProvider._endpointCache = {};
6263
});
6364

6465
it('conforms to ImageryProvider interface', function() {
@@ -117,6 +118,40 @@ defineSuite([
117118
});
118119
});
119120

121+
it('Uses previously fetched endpoint cache', function() {
122+
var endpointData = {
123+
type: 'IMAGERY',
124+
url: 'http://test.invalid/layer',
125+
accessToken: 'not_really_a_refresh_token',
126+
attributions: []
127+
};
128+
129+
var assetId = 12335;
130+
var options = { assetId: assetId, accessToken: 'token', server: 'http://test.invalid' };
131+
var endpointResource = IonResource._createEndpointResource(assetId, options);
132+
spyOn(IonResource, '_createEndpointResource').and.returnValue(endpointResource);
133+
spyOn(endpointResource, 'fetchJson').and.returnValue(when.resolve(endpointData));
134+
135+
expect(endpointResource.fetchJson.calls.count()).toBe(0);
136+
var provider = new IonImageryProvider(options);
137+
var provider2;
138+
return provider.readyPromise
139+
.then(function() {
140+
expect(provider.ready).toBe(true);
141+
expect(endpointResource.fetchJson.calls.count()).toBe(1);
142+
143+
// Same as options but in a different order to verify cache is order independant.
144+
var options2 = { accessToken: 'token', server: 'http://test.invalid', assetId: assetId };
145+
provider2 = new IonImageryProvider(options2);
146+
return provider2.readyPromise;
147+
})
148+
.then(function() {
149+
//Since the data is cached, fetchJson is not called again.
150+
expect(endpointResource.fetchJson.calls.count()).toBe(1);
151+
expect(provider2.ready).toBe(true);
152+
});
153+
});
154+
120155
it('propagates called to underlying imagery provider resolves when ready', function() {
121156
var provider = createTestProvider();
122157
var internalProvider;

0 commit comments

Comments
 (0)