Skip to content

Instantly share code, notes, and snippets.

@springmeyer
Created October 25, 2012 05:40
Show Gist options
  • Save springmeyer/3950618 to your computer and use it in GitHub Desktop.
Save springmeyer/3950618 to your computer and use it in GitHub Desktop.
tilelive-mapnik image pool
diff --git a/lib/render.js b/lib/render.js
index cd74f80..dec3af2 100644
--- a/lib/render.js
+++ b/lib/render.js
@@ -1,6 +1,7 @@
var mapnik = require('mapnik');
var _ = require('underscore');
var Step = require('step');
+var Pool = require('generic-pool').Pool;
var MapnikSource = require('./mapnik_backend');
var solidCache = {};
@@ -11,6 +12,53 @@ var EARTH_CIRCUMFERENCE = EARTH_DIAMETER * Math.PI;
var MAX_RES = EARTH_CIRCUMFERENCE / 256;
var ORIGIN_SHIFT = EARTH_CIRCUMFERENCE/2;
+var image_pools = function(size) {
+ return {
+ max: size || 5,
+ pools: {},
+ acquire: function(id, options, callback) {
+ if (!this.pools[id]) {
+ var that = this;
+ this.pools[id] = Pool({
+ name: id,
+ create: function(cb) { cb(null,new mapnik.Image(id,id)) },
+ destroy: function(obj) { delete obj },
+ max: that.max,
+ idleTimeoutMillis: options.idleTimeoutMillis || 5000,
+ log: false
+ //reapIntervalMillis
+ //priorityRange
+ });
+ }
+ this.pools[id].acquire(callback, options.priority || 0);
+ },
+ release: function(id, obj) {
+ var p = this.pools[id];
+ if (p) {
+ p.release(obj);
+ if (p.waitingClientsCount() > 0) {
+ console.log(id + ': pool size: ' + p.getPoolSize());
+ console.log(id + ': available: ' + p.availableObjectsCount());
+ console.log(id + ': waiting : ' + p.waitingClientsCount());
+ }
+ // todo - cleanup unused pool for a given id
+ }
+ },
+ drain: function() {
+ for (obj in this.pools) {
+ var p = this.pools[obj];
+ p.drain(function () {
+ p.destroyAllNow(function() {
+ });
+ });
+ };
+ }
+ };
+};
+
+var images = image_pools(20);
+//Math.ceil(Math.max(10, require('os').cpus().length * 2))
+
exports['calculateMetatile'] = calculateMetatile;
function calculateMetatile(options) {
@@ -119,58 +167,88 @@ MapnikSource.prototype._renderMetatile = function(options, callback) {
// Calculate bbox from xyz, respecting metatile settings.
var meta = calculateMetatile(options);
-
- // Set default options.
- if (options.format === 'utf') {
- options.layer = source._info.interactivity_layer;
- options.fields = source._info.interactivity_fields;
- options.resolution = source._uri.query.resolution;
- options.headers = { 'Content-Type': 'text/javascript; charset=utf-8' };
- var image = new mapnik.Grid(meta.width, meta.height);
- } else {
- options.headers = { 'Content-Type': 'image/png' };
- if (options.format.indexOf('jpeg') != -1) {
- options.headers = { 'Content-Type': 'image/jpeg' };
- }
- var image = new mapnik.Image(meta.width, meta.height);
- }
-
options.scale = source._uri.query.scale;
-
// Add reference to the source allowing debug/stat reporting to be compiled.
options.source = source;
process.nextTick(function() {
source._pool.acquire(function(err, map) {
if (err) return callback(err);
-
// Begin at metatile boundary.
options.x = meta.x;
options.y = meta.y;
-
map.resize(meta.width, meta.height);
+ //console.log('w: ' + meta.width + " h: " + meta.height);
map.extent = meta.bbox;
- try {
- source._stats.render++;
- map.render(image, options, function(err, image) {
- process.nextTick(function() {
- // Release after the .render() callback returned
- // to avoid mapnik errors.
- source._pool.release(map);
+ // Set default options.
+ if (options.format === 'utf') {
+ options.layer = source._info.interactivity_layer;
+ options.fields = source._info.interactivity_fields;
+ options.resolution = source._uri.query.resolution;
+ options.headers = { 'Content-Type': 'text/javascript; charset=utf-8' };
+ var image = new mapnik.Grid(meta.width, meta.height);
+ try {
+ source._stats.render++;
+ map.render(image, options, function(err, image) {
+ process.nextTick(function() {
+ // Release after the .render() callback returned
+ // to avoid mapnik errors.
+ source._pool.release(map);
+ });
+ if (err) return callback(err);
+ if (meta.tiles.length > 1) {
+ sliceMetatile(image, options, meta, callback);
+ } else {
+ encodeSingleTile(image, options, meta, callback);
+ }
});
+ } catch(err) {
+ source._pool.release(map);
+ callback(err);
+ }
- if (err) return callback(err);
-
- if (meta.tiles.length > 1) {
- sliceMetatile(image, options, meta, callback);
- } else {
- encodeSingleTile(image, options, meta, callback);
+ } else {
+ options.headers = { 'Content-Type': 'image/png' };
+ if (options.format.indexOf('jpeg') != -1) {
+ options.headers = { 'Content-Type': 'image/jpeg' };
+ }
+ images.acquire(meta.width,{},function(err,image) {
+ if (err) {
+ images.release(meta.width,image);
+ return callback(err);
+ }
+ if (image.reused) {
+ image.clear();
+ }
+ image.reused = true;
+ try {
+ source._stats.render++;
+ map.render(image, options, function(err, image) {
+ process.nextTick(function() {
+ // Release after the .render() callback returned
+ // to avoid mapnik errors.
+ source._pool.release(map);
+ });
+ if (err) return callback(err);
+ if (meta.tiles.length > 1) {
+ sliceMetatile(image, options, meta, function(err,tiles) {
+ images.release(meta.width,image);
+ callback(err,tiles);
+ });
+ } else {
+ encodeSingleTile(image, options, meta, function(err,tiles) {
+ images.release(meta.width,image);
+ callback(err,tiles);
+ });
+ }
+ });
+ } catch(err) {
+ source._pool.release(map);
+ images.release(meta.width,image);
+ callback(err);
}
});
- } catch(err) {
- source._pool.release(map);
- callback(err);
}
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment