@thermopylae/lib.cache
Version:
105 lines (104 loc) • 3.82 kB
JavaScript
import { DoublyLinkedList } from "../../data-structures/list/doubly-linked.js";
import { CircularBuffer } from "../../data-structures/circular-buffer.js";
import { createException } from "../../error.js";
const SEGMENT_TYPE_SYM = Symbol('ARC_SEGMENT_TYPE_SYM');
class ArcEvictionPolicy {
segments;
deleteFromCache;
constructor(cacheMaxCapacity) {
if (cacheMaxCapacity < 2) {
throw createException("INVALID_CACHE_MAX_CAPACITY" , `Cache maximum capacity needs to be at least 2.`);
}
this.segments = {
[0 ]: {
capacity: Math.round(cacheMaxCapacity / 2),
block: new DoublyLinkedList(),
ghosts: new CircularBuffer(Math.round(cacheMaxCapacity / 2))
},
[1 ]: {
capacity: 0,
block: new DoublyLinkedList(),
ghosts: new CircularBuffer(Math.round(cacheMaxCapacity / 2))
}
};
this.segments[1 ].capacity = cacheMaxCapacity - this.segments[0 ].capacity;
}
onHit(entry) {
if (entry[SEGMENT_TYPE_SYM] === 0 ) {
if (this.segments[1 ].capacity === 0) {
this.segments[0 ].block.toTail(entry);
return 1 ;
}
this.segments[0 ].block.remove(entry);
this.insertInT2(entry);
return 1 ;
}
this.segments[1 ].block.toFront(entry);
return 1 ;
}
onMiss(key) {
if (this.segments[0 ].ghosts.has(key)) {
if (this.segments[1 ].capacity === 0) {
return;
}
this.segments[0 ].capacity += 1;
this.segments[1 ].capacity -= 1;
if (this.segments[1 ].block.size > this.segments[1 ].capacity) {
this.deleteFromCache(this.segments[1 ].block.tail);
}
return;
}
if (this.segments[1 ].ghosts.has(key)) {
if (this.segments[0 ].capacity === 0) {
return;
}
this.segments[1 ].capacity += 1;
this.segments[0 ].capacity -= 1;
if (this.segments[0 ].block.size > this.segments[0 ].capacity) {
this.deleteFromCache(this.segments[0 ].block.head);
}
}
}
onSet(entry) {
this.insertInT1(entry);
}
onUpdate() {
return undefined;
}
onDelete(entry) {
this.segments[entry[SEGMENT_TYPE_SYM]].block.remove(entry);
this.segments[entry[SEGMENT_TYPE_SYM]].ghosts.add(entry.key);
entry[SEGMENT_TYPE_SYM] = undefined;
}
onClear() {
this.segments[0 ].block.clear();
this.segments[0 ].ghosts.clear();
this.segments[1 ].block.clear();
this.segments[1 ].ghosts.clear();
const cacheMaxCapacity = this.segments[0 ].capacity + this.segments[1 ].capacity;
this.segments[0 ].capacity = Math.round(cacheMaxCapacity / 2);
this.segments[1 ].capacity = cacheMaxCapacity - this.segments[0 ].capacity;
}
setDeleter(deleter) {
this.deleteFromCache = deleter;
}
insertInT1(entry) {
if (this.segments[0 ].capacity === 0) {
this.insertInT2(entry);
return;
}
if (this.segments[0 ].block.size === this.segments[0 ].capacity) {
this.deleteFromCache(this.segments[0 ].block.head);
}
entry[SEGMENT_TYPE_SYM] = 0 ;
this.segments[0 ].block.push(entry);
}
insertInT2(entry) {
if (this.segments[1 ].block.size === this.segments[1 ].capacity) {
this.deleteFromCache(this.segments[1 ].block.tail);
}
entry[SEGMENT_TYPE_SYM] = 1 ;
this.segments[1 ].block.unshift(entry);
}
}
export { ArcEvictionPolicy, SEGMENT_TYPE_SYM };