Named map mapconfig provider takes care of template modifications
If a template changes it will flush the provider so it recreates the mapconfig
This commit is contained in:
parent
84bf375f72
commit
f553efa69e
24
lib/cartodb/cache/named_map_provider_cache.js
vendored
24
lib/cartodb/cache/named_map_provider_cache.js
vendored
@ -2,6 +2,7 @@ var _ = require('underscore');
|
||||
var dot = require('dot');
|
||||
var NamedMapMapConfigProvider = require('../models/mapconfig/named_map_provider');
|
||||
var templateName = require('../backends/template_maps').templateName;
|
||||
var queue = require('queue-async');
|
||||
|
||||
var LruCache = require("lru-cache");
|
||||
|
||||
@ -34,9 +35,30 @@ NamedMapProviderCache.prototype.get = function(user, templateId, config, authTok
|
||||
params
|
||||
);
|
||||
this.providerCache.set(namedMapKey, namedMapProviders);
|
||||
|
||||
// early exit, if provider did not exist we just return it
|
||||
return callback(null, namedMapProviders[providerKey]);
|
||||
}
|
||||
|
||||
return callback(null, namedMapProviders[providerKey]);
|
||||
var namedMapProvider = namedMapProviders[providerKey];
|
||||
|
||||
var self = this;
|
||||
queue(2)
|
||||
.defer(namedMapProvider.getTemplate.bind(namedMapProvider))
|
||||
.defer(this.templateMaps.getTemplate.bind(this.templateMaps), user, templateId)
|
||||
.awaitAll(function templatesQueueDone(err, results) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// We want to reset provider its template has changed
|
||||
// Ideally this should be done in a passive mode where this cache gets notified of template changes
|
||||
var uniqueFingerprints = _.uniq(results.map(self.templateMaps.fingerPrint)).length;
|
||||
if (uniqueFingerprints > 1) {
|
||||
namedMapProvider.reset();
|
||||
}
|
||||
return callback(null, namedMapProvider);
|
||||
});
|
||||
};
|
||||
|
||||
NamedMapProviderCache.prototype.invalidate = function(user, templateId) {
|
||||
|
@ -152,6 +152,17 @@ NamedMapMapConfigProvider.prototype.getCacheBuster = function() {
|
||||
return this.cacheBuster;
|
||||
};
|
||||
|
||||
NamedMapMapConfigProvider.prototype.reset = function() {
|
||||
this.template = null;
|
||||
|
||||
this.affectedTablesAndLastUpdate = null;
|
||||
|
||||
this.err = null;
|
||||
this.mapConfig = null;
|
||||
|
||||
this.cacheBuster = Date.now();
|
||||
};
|
||||
|
||||
NamedMapMapConfigProvider.prototype.filter = function(key) {
|
||||
var regex = new RegExp('^' + this.createKey(true) + '.*');
|
||||
return key && key.match(regex);
|
||||
|
140
test/acceptance/named_maps_cache.js
Normal file
140
test/acceptance/named_maps_cache.js
Normal file
@ -0,0 +1,140 @@
|
||||
require('../support/test_helper');
|
||||
var RedisPool = require('redis-mpool');
|
||||
|
||||
var assert = require('../support/assert');
|
||||
var mapnik = require('windshaft').mapnik;
|
||||
var CartodbWindshaft = require('../../lib/cartodb/server');
|
||||
var serverOptions = require('../../lib/cartodb/server_options');
|
||||
var server = new CartodbWindshaft(serverOptions);
|
||||
var TemplateMaps = require('../../lib/cartodb/backends/template_maps.js');
|
||||
|
||||
describe('named maps provider cache', function() {
|
||||
// configure redis pool instance to use in tests
|
||||
var redisPool = new RedisPool(global.environment.redis);
|
||||
|
||||
var templateMaps = new TemplateMaps(redisPool, {
|
||||
max_user_templates: global.environment.maxUserTemplates
|
||||
});
|
||||
|
||||
var username = 'localhost';
|
||||
var templateName = 'template_with_color';
|
||||
|
||||
var IMAGE_TOLERANCE = 20;
|
||||
|
||||
function createTemplate(color) {
|
||||
return {
|
||||
version: '0.0.1',
|
||||
name: templateName,
|
||||
auth: {
|
||||
method: 'open'
|
||||
},
|
||||
placeholders: {
|
||||
color: {
|
||||
type: "css_color",
|
||||
default: color
|
||||
}
|
||||
},
|
||||
layergroup: {
|
||||
layers: [
|
||||
{
|
||||
type: 'mapnik',
|
||||
options: {
|
||||
sql: 'select * from populated_places_simple_reduced',
|
||||
cartocss: '#layer { marker-fill: <%= color %>; marker-line-color: <%= color %>; }',
|
||||
cartocss_version: '2.3.0'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(function (done) {
|
||||
templateMaps.delTemplate(username, templateName, done);
|
||||
});
|
||||
|
||||
function getNamedTile(options, callback) {
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
var url = '/api/v1/map/named/' + templateName + '/all/' + [0,0,0].join('/') + '.png';
|
||||
|
||||
var requestOptions = {
|
||||
url: url,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
host: username
|
||||
},
|
||||
encoding: 'binary'
|
||||
};
|
||||
|
||||
var statusCode = options.statusCode || 200;
|
||||
|
||||
var expectedResponse = {
|
||||
status: statusCode,
|
||||
headers: {
|
||||
'Content-Type': statusCode === 200 ? 'image/png' : 'application/json; charset=utf-8'
|
||||
}
|
||||
};
|
||||
|
||||
assert.response(server, requestOptions, expectedResponse, function (res, err) {
|
||||
var img;
|
||||
if (statusCode === 200) {
|
||||
img = mapnik.Image.fromBytes(new Buffer(res.body, 'binary'));
|
||||
}
|
||||
return callback(err, res, img);
|
||||
});
|
||||
}
|
||||
|
||||
function previewFixture(color) {
|
||||
return './test/fixtures/provider/populated_places_simple_reduced-' + color + '.png';
|
||||
}
|
||||
|
||||
var colors = ['red', 'red', 'green', 'blue'];
|
||||
colors.forEach(function(color) {
|
||||
it('should return an image estimating its bounds based on dataset', function (done) {
|
||||
templateMaps.addTemplate(username, createTemplate(color), function (err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
getNamedTile(function(err, res, img) {
|
||||
assert.ok(!err);
|
||||
assert.imageIsSimilarToFile(img, previewFixture(color), IMAGE_TOLERANCE, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail to use template from named map provider after template deletion', function (done) {
|
||||
var color = 'black';
|
||||
templateMaps.addTemplate(username, createTemplate(color), function (err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
getNamedTile(function(err, res, img) {
|
||||
assert.ok(!err);
|
||||
assert.imageIsSimilarToFile(img, previewFixture(color), IMAGE_TOLERANCE, function(err) {
|
||||
assert.ok(!err);
|
||||
|
||||
templateMaps.delTemplate(username, templateName, function (err) {
|
||||
assert.ok(!err);
|
||||
|
||||
getNamedTile({ statusCode: 404 }, function(err, res) {
|
||||
assert.ok(!err);
|
||||
assert.deepEqual(
|
||||
JSON.parse(res.body),
|
||||
{ errors: ["Template 'template_with_color' of user 'localhost' not found"] }
|
||||
);
|
||||
|
||||
// add template again so it's clean in afterEach
|
||||
templateMaps.addTemplate(username, createTemplate(color), done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
BIN
test/fixtures/provider/populated_places_simple_reduced-black.png
vendored
Normal file
BIN
test/fixtures/provider/populated_places_simple_reduced-black.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
test/fixtures/provider/populated_places_simple_reduced-blue.png
vendored
Normal file
BIN
test/fixtures/provider/populated_places_simple_reduced-blue.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
test/fixtures/provider/populated_places_simple_reduced-green.png
vendored
Normal file
BIN
test/fixtures/provider/populated_places_simple_reduced-green.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
test/fixtures/provider/populated_places_simple_reduced-red.png
vendored
Normal file
BIN
test/fixtures/provider/populated_places_simple_reduced-red.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in New Issue
Block a user