From 52345eaf5c857cb7d3e84a2051fec756bb6888cc Mon Sep 17 00:00:00 2001 From: Eduardo Nunes Date: Tue, 21 Jul 2015 11:25:51 -0300 Subject: [PATCH] fixed issue regarding concurrent requests to dns --- lib/index.js | 358 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 212 insertions(+), 146 deletions(-) diff --git a/lib/index.js b/lib/index.js index eb34309..33a20f9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,6 +7,12 @@ var CacheObject = require('./cache.js'), dns = require('dns'); +/* + * Stores the list of callbacks waiting for a dns call. + */ +var callbackList = {}; + + /* * Make a deep copy of the supplied object. This function reliably copies only * what is valid for a JSON object, array, or other element. @@ -49,7 +55,7 @@ var EnhanceDns = function (conf) { //cache already exists, means this code has already execute ie method are already overwritten return dns; } - + // original function storage var backup_object = { lookup : dns.lookup, @@ -65,7 +71,7 @@ var EnhanceDns = function (conf) { }, // cache storage instance cache = conf.cache ? new conf.cache(conf) : new CacheObject(conf); - + // insert cache object to the instance dns.internalCache = cache; @@ -94,23 +100,29 @@ var EnhanceDns = function (conf) { } } - cache.get('lookup_' + domain + '_' + family, function (error, record) { - if (record) { - callback(error, record.address, record.family); - } else { - backup_object.lookup(domain, family, function (err, address, family_r) { - if (err) { - callback(err); - } else { - cache.set('lookup_' + domain + '_' + family, { - 'address' : address, - 'family' : family_r - }, function () { - callback(err, address, family_r); - }); - } - }); - } + var key = 'lookup_' + domain + '_' + family; + cache.get(key, function (error, record) { + if (record) { return callback(error, record.address, record.family); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.lookup(domain, family, function (err, address, family_r) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('lookup_' + domain + '_' + family, { + 'address' : address, + 'family' : family_r + }, function () { + list.forEach(function (cb) { cb(err, address, family_r); }); + delete callbackList[key]; + }); + } + }); }); }; @@ -126,172 +138,226 @@ var EnhanceDns = function (conf) { callback_new = type; } - cache.get('resolve_' + domain + '_' + type_new, function (error, record) { - if (record) { - callback_new(error, deepCopy(record), true); - } else { - backup_object.resolve(domain, type_new, function (err, addresses) { - if (err) { - callback_new(err); - } else { - cache.set('resolve_' + domain + '_' + type_new, addresses, function () { - callback_new(err, deepCopy(addresses), false); - }); - } - }); - } + var key = 'resolve_' + domain + '_' + type_new; + cache.get(key, function (error, record) { + if (record) { return callback_new(error, deepCopy(record), true); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback_new); + + if (list.length > 1) { return; } + + backup_object.resolve(domain, type_new, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolve_' + domain + '_' + type_new, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses), false); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolve4 method dns.resolve4 = function (domain, callback) { - cache.get('resolve4_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolve4(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolve4_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolve4_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolve4(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolve4_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolve6 method dns.resolve6 = function (domain, callback) { - cache.get('resolve6_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolve6(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolve6_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolve6_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolve6(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolve6_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolveMx method dns.resolveMx = function (domain, callback) { - cache.get('resolveMx_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolveMx(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolveMx_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolveMx_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolveMx(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolveMx_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolveTxt method dns.resolveTxt = function (domain, callback) { - cache.get('resolveTxt_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolveTxt(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolveTxt_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolveTxt_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolveTxt(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolveTxt_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolveSrv method dns.resolveSrv = function (domain, callback) { - cache.get('resolveSrv_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolveSrv(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolveSrv_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolveSrv_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolveSrv(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolveSrv_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolveNs method dns.resolveNs = function (domain, callback) { - cache.get('resolveNs_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolveNs(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolveNs_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolveNs_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolveNs(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolveNs_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.resolveCname method dns.resolveCname = function (domain, callback) { - cache.get('resolveCname_' + domain, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.resolveCname(domain, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('resolveCname_' + domain, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'resolveCname_' + domain; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.resolveCname(domain, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('resolveCname_' + domain, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; // override dns.reverse method dns.reverse = function (ip, callback) { - cache.get('reverse_' + ip, function (error, record) { - if (record) { - callback(error, deepCopy(record)); - } else { - backup_object.reverse(ip, function (err, addresses) { - if (err) { - callback(err); - } else { - cache.set('reverse_' + ip, addresses, function () { - callback(err, deepCopy(addresses)); - }); - } - }); - } + var key = 'reverse_' + ip; + cache.get(key, function (error, record) { + if (record) { return callback(error, deepCopy(record)); } + + var list = callbackList[key] = callbackList[key] || []; + list.push(callback); + + if (list.length > 1) { return; } + + backup_object.reverse(ip, function (err, addresses) { + if (err) { + list.forEach(function (cb) { cb(err); }); + delete callbackList[key]; + } else { + cache.set('reverse_' + ip, addresses, function () { + list.forEach(function (cb) { cb(err, deepCopy(addresses)); }); + delete callbackList[key]; + }); + } + }); }); }; return dns; @@ -299,4 +365,4 @@ var EnhanceDns = function (conf) { module.exports = function(conf) { return new EnhanceDns(conf); -}; \ No newline at end of file +};