2q-cache
Version:
Imlementation of 2Q Cache Algorithm
167 lines (142 loc) • 5.06 kB
text/typescript
import { CacheQueue } from "../utils/cache_queue";
import { CacheMapElem, CacheQueueElem, BucketsTransportObject } from "../utils/cache_objects";
export class CacheBuckets {
private in : CacheQueue;
private out : CacheQueue;
private searcher : Map<any, CacheMapElem>;
constructor(inSize, outSize) {
this.in = new CacheQueue(inSize);
this.out = new CacheQueue(outSize);
this.searcher = new Map();
}
public set(key : any, value : any, ttl : number = 0) : boolean {
let oldMapElem = this.searcher.get(key);
if (!oldMapElem) {
let newQueueElem = new CacheQueueElem();
newQueueElem.key = key;
let newMapElem = new CacheMapElem();
newMapElem.bucket = 0;
newMapElem.linkToList = newQueueElem;
newMapElem.data = value;
clearTimeout(newMapElem.timeout);
if (ttl > 0) {
newMapElem.timeout = setTimeout(() => {
if (this.has(key)) this.delete(key);
},ttl)
}
let repressedElem = this.in.push(newQueueElem);
this.pushToOut(repressedElem);
this.searcher.set(key, newMapElem);
} else {
oldMapElem.data = value;
clearTimeout(oldMapElem.timeout);
if (ttl > 0) {
oldMapElem.timeout = setTimeout(() => {
if (this.has(key)) this.delete(key);
},ttl)
}
this.searcher.set(key, oldMapElem);
}
return true;
}
updateTtl(key : any, ttl : any) {
let mapElem = this.searcher.get(key);
if (mapElem) {
clearTimeout(mapElem.timeout);
if (ttl > 0) {
mapElem.timeout = setTimeout(() => {
if (this.has(key)) this.delete(key);
},ttl)
}
}
}
private pushToOut(elem : CacheQueueElem) : void {
if (elem != null) {
this.searcher.get(elem.key).bucket = 1;
let repressedElem = this.out.push(elem);
if (repressedElem != null) {
this.searcher.delete(repressedElem.key);
}
}
}
public get(key : any) : BucketsTransportObject {
let foundElem = this.searcher.get(key);
if (foundElem) {
let transport = new BucketsTransportObject();
transport.key = key;
transport.value = foundElem.data;
let bucket = foundElem.bucket;
if (bucket === 1) {
clearTimeout(foundElem.timeout);
this.out.unlink(foundElem.linkToList);
this.searcher.delete(key);
transport.needMove = true;
}
return transport;
}
return null;
}
public has(key : any) : boolean {
return this.searcher.has(key);
}
public clear() : void {
this.searcher.forEach(value => {
clearTimeout(value.timeout);
})
this.searcher.clear();
this.in.clear();
this.out.clear();
}
public delete(key : any) : boolean {
let delObject = this.searcher.get(key);
clearTimeout(delObject.timeout);
if (delObject.bucket === 0) {
this.in.unlink(delObject.linkToList);
this.searcher.delete(key);
} else {
this.out.unlink(delObject.linkToList);
this.searcher.delete(key);
}
return true;
}
public getSize() : Array<number> {
return [
this.in.getSize(),
this.out.getSize()
];
}
public getMaxSize() : Array<number> {
return [
this.in.getMaxSize(),
this.out.getMaxSize()
];
}
public getSizeObject() : object {
return {
in : {
currentSize : this.in.getSize(),
maxSize : this.in.getMaxSize()
},
out : {
currentSize : this.out.getSize(),
maxSize : this.out.getMaxSize()
}
}
}
public setSize(inSize : number, outSize : number) {
this.in.setSize(inSize);
while (this.in.getSize() > this.in.getMaxSize()) {
let deletedElem = this.in.pop();
let dElem = this.searcher.get(deletedElem.key);
if (dElem) clearTimeout(dElem.timeout);
this.searcher.delete(deletedElem.key);
}
this.out.setSize(outSize);
while (this.out.getSize() > this.out.getMaxSize()) {
let deletedElem = this.out.pop();
let dElem = this.searcher.get(deletedElem.key);
if (dElem) clearTimeout(dElem.timeout);
this.searcher.delete(deletedElem.key);
}
}
}