mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-04-22 09:35:10 +01:00
98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
/**
|
|
* Utility to cache array of objects associated to a key.
|
|
* We use it to cache array of edge/vertex pairs (outE or inE)
|
|
* Cache size is capped to a maximum.
|
|
*/
|
|
export class ArraysByKeyCache<T> {
|
|
private cache: { [key: string]: T[] };
|
|
private keyQueue: string[]; // Last touched key FIFO to purge cache if too big.
|
|
private totalElements: number;
|
|
private maxNbElements: number;
|
|
|
|
public constructor(maxNbElements: number) {
|
|
this.maxNbElements = maxNbElements;
|
|
this.clear();
|
|
}
|
|
|
|
public clear(): void {
|
|
this.cache = {};
|
|
this.keyQueue = [];
|
|
this.totalElements = 0;
|
|
}
|
|
|
|
/**
|
|
* To simplify, the array of cached elements array for a given key is dense (there is no index at which an elemnt is missing).
|
|
* Retrieving a page within the array is guaranteed to return a complete page.
|
|
* @param key
|
|
* @param newElt
|
|
* @param index
|
|
*/
|
|
public insert(key: string, index: number, newElt: T): void {
|
|
const elements: T[] = this.cache[key] || [];
|
|
this.cache[key] = elements;
|
|
|
|
if (index < 0) {
|
|
console.error("Inserting with negative index is not allowed by ArraysByCache");
|
|
return;
|
|
}
|
|
|
|
// Check that previous index is populated, if not, ignore
|
|
if (index > elements.length) {
|
|
console.error("Inserting non-contiguous element is not allowed by ArraysByCache");
|
|
return;
|
|
}
|
|
|
|
// Update last updated
|
|
this.markKeyAsTouched(key);
|
|
|
|
if (this.totalElements + 1 > this.maxNbElements && key !== this.keyQueue[0]) {
|
|
this.reduceCacheSize();
|
|
}
|
|
|
|
elements[index] = newElt;
|
|
this.totalElements++;
|
|
}
|
|
|
|
/**
|
|
* Retrieve a page of elements.
|
|
* Return array of elements or null. null means "complete page not found in cache".
|
|
* @param key
|
|
* @param startIndex
|
|
* @param pageSize
|
|
*/
|
|
public retrieve(key: string, startIndex: number, pageSize: number): T[] {
|
|
if (!this.cache.hasOwnProperty(key)) {
|
|
return null;
|
|
}
|
|
const elements = this.cache[key];
|
|
if (startIndex + pageSize > elements.length) {
|
|
return null;
|
|
}
|
|
|
|
return elements.slice(startIndex, startIndex + pageSize);
|
|
}
|
|
|
|
/**
|
|
* Invalidate elements to keep the total number below the limit
|
|
* TODO: instead of invalidating the entire array, remove only needed number of elements
|
|
*/
|
|
private reduceCacheSize(): void {
|
|
// remove an key and its array
|
|
const oldKey = this.keyQueue.shift();
|
|
this.totalElements -= this.cache[oldKey].length;
|
|
delete this.cache[oldKey];
|
|
}
|
|
|
|
/**
|
|
* Bubble up this key as new.
|
|
* @param key
|
|
*/
|
|
private markKeyAsTouched(key: string) {
|
|
const n = this.keyQueue.indexOf(key);
|
|
if (n > -1) {
|
|
this.keyQueue.splice(n, 1);
|
|
}
|
|
this.keyQueue.push(key);
|
|
}
|
|
}
|