mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-01 01:58:11 +08:00
Bkmartinjr/state mgr tests (#298)
Jest tests for part of util/stateManager * reorganize test directories * lint * add Jest config to eslint * add Jest config to eslint * lint * fix babel configuration for tests * start at kvCache tests * reorganize test directories * lint * add Jest config to eslint * add Jest config to eslint * lint * fix babel configuration for tests * start at kvCache tests * fix cache flush bug manifest by new test cases * new kvCache tests * skeletal universe test * fix race in test case * more universe test cases
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
import _ from "lodash";
|
||||
|
||||
/*
|
||||
Very simple key/value cache for use by World & Universe.
|
||||
Very simple key/value cache for use by World & Universe. Cache keys must
|
||||
be a string, and values are any JS non-primitive value.
|
||||
|
||||
* constructor(lowWatermark, minTTL):
|
||||
- lowWatermark defines the number of cache elements below which
|
||||
@@ -18,8 +19,21 @@ Very simple key/value cache for use by World & Universe.
|
||||
*/
|
||||
|
||||
const cachePrivateKey = "__kvcachekey__";
|
||||
const defaultLowWatermark = 32;
|
||||
const defaultMinTTL = 1000;
|
||||
|
||||
function create(lowWatermark = defaultLowWatermark, minTTL = defaultMinTTL) {
|
||||
if (typeof minTTL !== "number" || typeof lowWatermark !== "number") {
|
||||
throw new TypeError(
|
||||
"minTTL and lowWatermark parameters must be a primitive number"
|
||||
);
|
||||
}
|
||||
if (lowWatermark < 0 || minTTL < 0) {
|
||||
throw new RangeError(
|
||||
"minTTL and lowWatermark parameters must be number greater than zero"
|
||||
);
|
||||
}
|
||||
|
||||
function create(lowWatermark = 32, minTTL = 1000) {
|
||||
return {
|
||||
[cachePrivateKey]: {
|
||||
lowWatermark,
|
||||
@@ -29,6 +43,10 @@ function create(lowWatermark = 32, minTTL = 1000) {
|
||||
}
|
||||
|
||||
function get(kvcache, key) {
|
||||
if (key === cachePrivateKey) {
|
||||
throw new RangeError(`key parameter may not have value ${cachePrivateKey}`);
|
||||
}
|
||||
|
||||
const val = kvcache[key];
|
||||
if (val) {
|
||||
val[cachePrivateKey] = Date.now();
|
||||
@@ -37,10 +55,20 @@ function get(kvcache, key) {
|
||||
}
|
||||
|
||||
function set(kvcache, key, val) {
|
||||
if (key === cachePrivateKey) {
|
||||
throw new RangeError(`key parameter may not have value ${cachePrivateKey}`);
|
||||
}
|
||||
|
||||
const newKvCache = { ...kvcache };
|
||||
newKvCache[key] = val;
|
||||
val[cachePrivateKey] = Date.now();
|
||||
flush(newKvCache, newKvCache[cachePrivateKey].minTTL);
|
||||
flushInPlace(newKvCache);
|
||||
return newKvCache;
|
||||
}
|
||||
|
||||
function flush(kvcache) {
|
||||
const newKvCache = { ...kvcache };
|
||||
flushInPlace(newKvCache);
|
||||
return newKvCache;
|
||||
}
|
||||
|
||||
@@ -48,24 +76,24 @@ function set(kvcache, key, val) {
|
||||
Flush elements from cache IF cache size is greater than lowWatermark, and
|
||||
those elements are older than minAgeMS
|
||||
*/
|
||||
function flush(kvcache, minAgeMs = 0) {
|
||||
if (minAgeMs < 0) return kvcache;
|
||||
const eol = Date.now() - minAgeMs;
|
||||
const { lowWatermark } = kvcache[cachePrivateKey];
|
||||
const keys = _(kvcache)
|
||||
function flushInPlace(kvCache) {
|
||||
const { lowWatermark, minTTL } = kvCache[cachePrivateKey];
|
||||
const eol = Date.now() - minTTL;
|
||||
const allKeys = _(kvCache)
|
||||
.keys()
|
||||
.filter(k => k !== cachePrivateKey)
|
||||
.filter(k => kvcache[k][cachePrivateKey] < eol)
|
||||
.sortBy([k => kvcache[k][cachePrivateKey]])
|
||||
.sortBy([k => kvCache[k][cachePrivateKey]])
|
||||
.value();
|
||||
|
||||
if (keys.length > lowWatermark) {
|
||||
const numKeysToDelete = keys.length - lowWatermark;
|
||||
const keysToDelete = _.slice(keys, 0, numKeysToDelete);
|
||||
_.forEach(keysToDelete, k => delete kvcache[k]);
|
||||
if (allKeys.length > lowWatermark) {
|
||||
const keysToDelete = _(allKeys)
|
||||
.slice(0, allKeys.length - lowWatermark)
|
||||
.filter(k => kvCache[k][cachePrivateKey] <= eol)
|
||||
.value();
|
||||
_.forEach(keysToDelete, k => delete kvCache[k]);
|
||||
}
|
||||
|
||||
return kvcache;
|
||||
return kvCache;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -76,9 +104,15 @@ function map(srcKvCache, cb, createOptions) {
|
||||
.keys()
|
||||
.filter(k => k !== cachePrivateKey)
|
||||
.value();
|
||||
const newKvCache = create(createOptions.lowWatermark, createOptions.minTTL);
|
||||
const lowWatermark = _.get(
|
||||
createOptions,
|
||||
"lowWatermark",
|
||||
defaultLowWatermark
|
||||
);
|
||||
const minTTL = _.get(createOptions, "minTTL", defaultMinTTL);
|
||||
const newKvCache = create(lowWatermark, minTTL);
|
||||
_.forEach(keysInSrcKvCache, key => {
|
||||
const val = cb(get(srcKvCache, key));
|
||||
const val = cb(get(srcKvCache, key), key);
|
||||
newKvCache[key] = val;
|
||||
val[cachePrivateKey] = Date.now();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user