Permalink
Browse files

refactor cache/store, expose Lookup for servers

  • Loading branch information...
1 parent e19bf1c commit 7328b4366a5f905e4be0d14cfddfb1d6c45c13ee @tjfontaine committed Dec 28, 2012
Showing with 342 additions and 151 deletions.
  1. +7 −3 dns.js
  2. +126 −137 lib/cache.js
  3. +3 −1 lib/client.js
  4. +93 −0 lib/memory.js
  5. +1 −1 lib/packet.js
  6. +25 −6 lib/platform.js
  7. +86 −0 lib/utils.js
  8. +1 −1 package.json
  9. +0 −2 test/client.js
View
10 dns.js
@@ -101,7 +101,11 @@ exports.Question = function (opts) {
};
exports.Request = client.Request;
-var cache = require('./lib/cache');
+exports.Cache = require('./lib/cache');
+exports.MemoryStore = require('./lib/memory').MemoryStore;
-exports.Cache = cache.Cache;
-exports.MemoryStore = cache.MemoryStore;
+var utils = require('./lib/utils');
+
+exports.Lookup = utils.Lookup
+exports.is_absolute = utils.is_absolute;
+exports.ensure_absolute = utils.ensure_absolute;
View
@@ -20,176 +20,165 @@
'use strict';
-var consts = require('./consts'),
- util = require('util'),
- Heap = require('binaryheap');
+var MemoryStore = require('./memory').MemoryStore;
+var utils = require('./utils');
+var Lookup = utils.Lookup;
+var util = require('util');
+var Heap = require('binaryheap');
-var CNAME = consts.NAME_TO_QTYPE.CNAME;
-
-var debug = function() {
- //var args = Array.prototype.slice.call(arguments);
- //console.log.apply(this, ['cache', Date.now().toString()].concat(args));
+var MemoryStoreExpire = function (store, zone, opts) {
+ opts = opts || {};
+ this._store = store;
+ this._zone = zone;
+ this._max_keys = opts.max_keys;
+ this._ttl = new Heap(true);
};
-var extend = util._extend;
-
-if (!extend) {
- // shamelessly grabbed from joyent/node/lib/util.js
- extend = function(origin, add) {
- // Don't do anything if add isn't an object
- if (!add || typeof add !== 'object') return origin;
-
- var keys = Object.keys(add);
- var i = keys.length;
- while (i--) {
- origin[keys[i]] = add[keys[i]];
+MemoryStoreExpire.prototype.get = function (domain, key, cb) {
+ var self = this;
+ this._store.get(domain, key, function (err, results) {
+ var i, j, type, record;
+ var nresults = {};
+ var now = Date.now();
+
+ for (i in results) {
+ type = results[i];
+ for (j in type) {
+ record = type[j];
+ record.ttl = Math.round((record._ttl_expires - now) / 1000)
+ if (record.ttl > 0) {
+ if (!nresults[i]) {
+ nresults[i] = [];
+ }
+ nresults[i].push(record);
+ } else {
+ self._ttl.remove(record);
+ self._store.delete(self._zone, record.name, record.type, function () {});
+ }
+ }
}
- return origin;
- };
-}
-
-var MemoryStore = exports.MemoryStore = function(max, range) {
- this._max_keys = max || 1000;
- this._range = range || 50;
- this._index = {};
- this._ttl = new Heap(true);
-};
-MemoryStore.prototype._delete = function(name, type) {
- var entry = this._index[name + type];
- this._ttl.remove(entry);
- delete this._index[name + type];
+ cb(err, nresults);
+ });
};
-MemoryStore.prototype._trim = function() {
+MemoryStoreExpire.prototype.set = function (domain, key, data, cb) {
+ var i, j, type, record, expires;
var self = this;
- var remove_count = this._ttl.length - this._max_keys;
- var remove;
-
- if (remove_count > 0) {
- debug('memory store trim to remove', remove_count);
- while (remove_count > 0) {
- remove = this._ttl.pop();
- debug('memory store trim', remove);
- delete this._index[remove.name + remove.type];
- remove_count -= 1;
+ var now = Date.now();
+
+ for (i in data) {
+ type = data[i];
+ for (j in type) {
+ record = type[j];
+ expires = (record.ttl * 1000) + now;
+ record._ttl_expires = expires;
+ self._ttl.insert(record, expires);
}
}
-};
-MemoryStore.prototype.purge = function() {
- this._index = {};
- this._ttl = new Heap();
-};
-
-MemoryStore.prototype.get = function(name, type, cb) {
- var key = name + type;
- var value = this._index[key];
- var results;
-
- debug('memory store get', name, type);
-
- if (value) {
- if (Date.now() < value.expires || !value.expires) {
- results = value.values;
- } else {
- this._delete(name, type);
- }
+ while (this._ttl.length > this._max_keys) {
+ var record = this._ttl.pop();
+ this._store.delete(this._zone, record.name, record.type);
}
- process.nextTick(function() {
- cb(results);
+ this._store.set(domain, key, data, function (err, results) {
+ if (cb)
+ cb(err, results);
});
};
-MemoryStore.prototype.set = function(rr) {
- var name = rr.name,
- type = rr.type;
-
- var expires;
-
- if (rr.ttl !== false) {
- expires = Date.now() + (rr.ttl * 1000);
- } else {
- expires = false;
+MemoryStoreExpire.prototype.delete = function (domain, key, type, cb) {
+ if (!cb) {
+ cb = type;
+ type = undefined;
}
- var key = name + type;
- var value = this._index[key];
-
- debug('memory store set', name, type, expires);
+ var self = this;
- if (!value) {
- value = this._index[key] = {
- values: []
- };
+ this._store.get(domain, utils.ensure_absolute(key), function (gerr, gresults) {
+ var i, j, ktype, record;
- this._ttl.insert({
- name: name,
- type: type,
- ttl: expires
- }, expires);
+ for (i in gresults) {
+ ktype = gresults[i];
+ for (j in ktype) {
+ record = ktype[j];
+ self._ttl.remove(record);
+ }
+ }
- this._trim();
- }
+ if (!gresults) {
+ if (cb)
+ cb(gerr, gresults);
+ return;
+ }
- value.expires = expires;
- value.values.push(extend({}, rr));
+ self._store.delete(domain, key, type, function (err, results) {
+ if (cb)
+ cb(err, results);
+ });
+ });
};
-var Cache = exports.Cache = function(opts) {
+var Cache = module.exports = function (opts) {
opts = opts || {};
- this._store = opts.store || new MemoryStore();
+ this._zone = '.' || opts.zone;
+ this._store = undefined;
+ this.purge = function () {
+ this._store = new MemoryStoreExpire(opts.store || new MemoryStore(), this._zone, opts);
+ }
+ this.purge();
};
-var send = function(type, results, cb) {
- var i, packet;
+Cache.prototype.store = function (packet) {
+ var self = this;
+ var c = {};
+
+ function each(record) {
+ var r = c[record.name.toLowerCase()];
+ var t;
+
+ if (!r)
+ r = c[record.name.toLowerCase()] = {};
+
+ t = r[record.type];
+
+ if (!t)
+ t = r[record.type] = [];
- if (results.length) {
- cb(results)
- } else {
- cb(null);
+ t.push(record);
}
+
+ packet.answer.forEach(each);
+ packet.authority.forEach(each);
+ packet.additional.forEach(each);
+
+ Object.keys(c).forEach(function (key) {
+ self._store.set(self._zone, utils.ensure_absolute(key), c[key]);
+ });
};
-Cache.prototype.lookup = function(question, cb) {
+Cache.prototype.lookup = function (question, cb) {
var self = this;
- var results = [];
- var name = question.name.toLowerCase();
- var type = question.type;
-
- debug('cache lookup', name);
-
- var found_cname = function(result) {
- if (!result) {
- send(type, results, cb);
- } else {
- debug('cache found cname', name);
- results.push(result[0]);
- name = result[0].data;
- self._store.get(name, type, found_exact);
+ Lookup(this._store, this._zone, question, function (err, results) {
+ var i, record, found = false;
+
+ for (i in results) {
+ record = results[i];
+ if (record.type == question.type) {
+ found = true;
+ break;
+ }
}
- };
-
- var found_exact = function(result) {
- if (!result) {
- self._store.get(name, CNAME, found_cname);
- } else {
- debug('cache found', name, type);
- results = results.concat(result);
- send(type, results, cb);
- }
- };
-
- self._store.get(name, type, found_exact);
-};
-Cache.prototype.store = function(packet) {
- packet.answer.forEach(this._store.set.bind(this._store));
- packet.authority.forEach(this._store.set.bind(this._store));
- packet.additional.forEach(this._store.set.bind(this._store));
-};
+ if (results && !found) {
+ self._store.delete(self._zone, utils.ensure_absolute(question.name));
+ results.forEach(function (rr) {
+ self._store.delete(self._zone, utils.ensure_absolute(rr.name));
+ });
+ results = null;
+ }
-Cache.prototype.purge = function() {
- this._store.purge();
+ cb(results);
+ });
};
View
@@ -554,11 +554,13 @@ Lookup.prototype.start = function() {
platform.hosts.lookup(this.question, function(results) {
var packet;
- if (results) {
+ if (results && results.length) {
+ debug('Lookup in hosts', results);
packet = new Packet();
packet.answer = results.slice();
self._emit(null, packet);
} else {
+ debug('Lookup not in hosts');
Resolve.prototype.start.call(self);
}
});
Oops, something went wrong.

0 comments on commit 7328b43

Please sign in to comment.