UNPKG

2.68 kBJavaScriptView Raw
1// This code base means freedom.
2
3var
4 assert = require('assert'),
5 Skiplist = require('skiplist'),
6 Xxhash = require('xxhashjs').h64
7 ;
8
9var Lightcycle = module.exports = function Lightcycle(settings)
10{
11 settings = settings || {};
12
13 this.seed = settings.seed || 0xcafed00d;
14 this.size = Math.round(settings.size) || 128;
15 assert(this.size > 0, 'you must pass in a positive integer for size');
16
17 this.replicas = settings.replicas || this.size;
18 this.resources = new Skiplist(this.size * this.replicas + 16); // a little padding
19 this.cache = {};
20 this.entries = {};
21};
22
23Lightcycle.prototype.seed = 0xcafed00d;
24Lightcycle.prototype.size = 128;
25Lightcycle.prototype.replicas = 128;
26Lightcycle.prototype.resources = null;
27Lightcycle.prototype.cache = null;
28Lightcycle.prototype.entries = null;
29
30// Constants used when rebalancing to leave space.
31Lightcycle.SIZE_PAD = 16;
32Lightcycle.REPLICAS_PAD = 8;
33
34Lightcycle.prototype.add = function add(resource, id)
35{
36 assert(resource);
37 assert(id && typeof id === 'string');
38 if (!this.cache[id])
39 this.cache[id] = [];
40 var key;
41
42 for (var i = 0; i < this.replicas; i++)
43 {
44 if (this.cache[id][i])
45 key = this.cache[id][i];
46 else
47 {
48 key = this.hashit(id + String(i));
49 this.cache[id][i] = key;
50 }
51 this.resources.insert(key, resource);
52 }
53
54 this.entries[id] = resource;
55 if (Object.keys(this.entries).length > this.size)
56 this.rebalance();
57};
58
59Lightcycle.prototype.remove = function remove(id)
60{
61 assert(id && typeof id === 'string');
62 if (!Array.isArray(this.cache[id]))
63 return;
64 var key;
65
66 for (var i = 0; i < this.replicas; i++)
67 {
68 key = this.cache[id][i];
69 this.resources.remove(key);
70 }
71
72 delete this.entries[id];
73};
74
75Lightcycle.prototype.locate = function locate(id)
76{
77 var key = this.hashit(id);
78 var results = this.resources.findWithCount(key, 1);
79
80 if (results.length === 0)
81 results = this.resources.findWithCount(null, 1);
82
83 if (results.length > 0)
84 return results[0][1];
85
86 return null;
87};
88
89Lightcycle.prototype.hashit = function hashit(input)
90{
91 if (!Buffer.isBuffer(input))
92 input = new Buffer(input);
93
94 var hash = Xxhash(this.seed);
95 hash.update(input);
96 var result = hash.digest().toString(16);
97 while (result.length < 8) result = '0' + result;
98
99 return result;
100};
101
102Lightcycle.prototype.all = function all()
103{
104 return this.entries;
105};
106
107Lightcycle.prototype.rebalance = function rebalance()
108{
109 var ids = Object.keys(this.entries);
110
111 this.size = ids.length + Lightcycle.SIZE_PAD;
112 this.replicas = ids.length + Lightcycle.REPLICAS_PAD;
113 this.resources = new Skiplist(this.size * this.replicas);
114
115 for (var i = 0; i < ids.length; i++)
116 this.add(this.entries[ids[i]], ids[i]);
117};