-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
138 lines (130 loc) · 3.07 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
var fdll = require('fdll');
var events = require('events');
var util = require('util');
module.exports = ARC;
function ARC(c) {
this.c = c;
this.p = 0;
this.t1 = new fdll();
this.t2 = new fdll();
this.b1 = new fdll();
this.b2 = new fdll();
}
util.inherits(ARC, events.EventEmitter);
ARC.prototype._replace = function(key) {
var t1Length = this.t1.length();
var lru;
if (t1Length && (t1Length > this.p || (this.b2.get(key) && t1Length == this.p))) {
lru = this.t1.shift();
if (lru.data) this.emit('eviction', lru.key, lru.data);
lru.data = null;
this.b1.push(lru);
} else {
lru = this.t2.shift();
if (lru.data) this.emit('eviction', lru.key, lru.data);
lru.data = null;
this.b2.push(lru);
}
};
ARC.prototype.get = function(key) {
var keyData;
keyData = this.t1.get(key);
if (keyData) {
if (keyData.data == null) return null;
this.t2.push(this.t1.remove(key));
return keyData.data;
}
keyData = this.t2.get(key);
if (keyData) {
if (keyData.data == null) return null;
this.t2.push(this.t2.remove(key));
return keyData.data;
}
return;
};
ARC.prototype.peek = function(key) {
var keyData;
keyData = this.t1.get(key);
if (keyData) {
return keyData.data;
}
keyData = this.t2.get(key);
if (keyData) {
return keyData.data;
}
return;
};
ARC.prototype.del = function(key) {
return this.update(key, null);
};
ARC.prototype.update = function(key, val) {
var keyData;
keyData = this.t1.get(key);
if (keyData) {
return this.t1.set(key, val);
}
keyData = this.t2.get(key);
if (keyData) {
return this.t2.set(key, val);
}
return new Error('key should be in cache');
};
ARC.prototype.set = function(key, val) {
var keyData;
var delta;
//case I
if (this.t1.get(key) || this.t2.get(key)) {
return new Error('key should not be in cache');
}
//case II
keyData = this.b1.get(key);
if (keyData) {
var b1Length = this.b1.length();
var b2Length = this.b2.length();
delta = (b1Length >= b2Length) ? 1 : Math.floor(b2Length / b1Length);
this.p = Math.min(this.p + delta, this.c);
this._replace(key);
var keyData = this.b1.remove(key);
keyData.data = val;
this.t2.push(keyData);
return;
}
//case III
keyData = this.b2.get(key);
if (keyData) {
var b1Length = this.b1.length();
var b2Length = this.b2.length();
delta = (b2Length >= b1Length) ? 1 : Math.floor(b1Length / b2Length);
this.p = Math.max(this.p - delta, 0);
this._replace(key);
var keyData = this.b2.remove(key);
keyData.data = val;
this.t2.push(keyData);
return;
}
//case IV
var b1Length = this.b1.length();
var t1Length = this.t1.length();
var b2Length = this.b2.length();
var t2Length = this.t2.length();
if (b1Length + t1Length == this.c) {//case A
if (t1Length < this.c) {
this.b1.shift();
this._replace(key);
} else {
var lru = this.t1.shift();
if (lru.data) this.emit('eviction', lru.key, lru.data);
}
} else {//case B
var totalLength = b1Length + t1Length + b2Length + t2Length;
if (totalLength >= this.c) {
if (totalLength == 2 * this.c) this.b2.shift();
this._replace(key);
}
}
this.t1.push({
key: key,
data: val
});
return;
};