Name
sn_entitlement.MembershipInMemoryCache
Description
No description available
Script
/**
* This class is intended to contain membership relationships in a memory efficient manner so that they can be
* loaded into memory and used without incremental database calls for each request. The initial use case is to
* store userIds and the associated roleIds that the user has. However, this class is flexible enough to hold
* other types of data that conform to the same sort of relationship.
*/
var MembershipInMemoryCache = Class.create();
MembershipInMemoryCache.prototype = {
/**
* Constructor that takes a data provider and key/value names to load data from and cache in memory.
* Since this class doesn't need to know where the data is coming from, only how to retrieve it,
* the key/value names are to provide flexibility for varying data sources.
*
* @param glideRecord Glide record object that provides data
* @param keyName The name of the key for the data (e.g. userId)
* @param valName The name of the key for the value (e.g. roleId)
* @param maxValueCount The max number of values expected
*/
initialize: function(glideRecord, keyName, valName, maxValueCount) {
this._maxValueCount = maxValueCount;
this._bitmap = [];
this._loadData(glideRecord, keyName, valName, maxValueCount);
},
/**
* Retrieves the values associated with the provided id
*
* @param id The id to fetch data for. (e.g. userId)
*/
getValsById: function(id) {
if (!this._keys.has(id))
return null;
const keyIndex = this._keys.get(id);
let vals = [];
for (let valueIndex = 0; valueIndex < this._maxValueCount; valueIndex++) {
if (this._isSet(keyIndex, valueIndex))
vals.push(this._vals[valueIndex]);
}
return vals;
},
/**
* Load data into memory in an memory efficient manner.
*
* @param glideRecord Glide record object that provides data
* @param keyName The name of the key for the data (e.g. userId)
* @param valName The name of the key for the value (e.g. roleId)
*/
_loadData: function(glideRecord, keyName, valName) {
const keys = new Map();
const values = new Map();
while (glideRecord.next()) {
const key = glideRecord.getValue(keyName);
const val = glideRecord.getValue(valName);
if (!keys.has(key))
keys.set(key, keys.size);
if (!values.has(val))
values.set(val, values.size);
const keyIndex = keys.get(key);
const valueIndex = values.get(val);
this._ensureSize(keyIndex);
this._set(keyIndex, valueIndex);
}
this._keys = keys;
this._vals = [...values.keys()];
},
/**
* Ensure that there's enough array slots in this._bitmap which hold 32bit words
* to accomodate all values at specified keyIndex.
* Specifically, that there's enough space to hold (keyIndex+1) * this._maxValueCount bit.
* If this._bitmap is increased in size, the new array slots are initialized with 0.
*/
_ensureSize: function(keyIndex) {
const neededWords = Math.floor((this._maxValueCount * (keyIndex + 1) + 30) / 31);
if (neededWords > this._bitmap.length) {
const fillFrom = this._bitmap.length;
this._bitmap.length = neededWords;
this._bitmap.fill(0, fillFrom);
}
},
_set: function(keyIndex, valueIndex) {
const [wordIndex, bitIndex] = this._getIndex(keyIndex, valueIndex);
this._bitmap[wordIndex] |= 1 << bitIndex;
},
_unset: function(keyIndex, valueIndex) {
const [wordIndex, bitIndex] = this._getIndex(keyIndex, valueIndex);
this._bitmap[wordIndex] &= ~(1 << bitIndex);
},
_isSet: function(keyIndex, valueIndex) {
const [wordIndex, bitIndex] = this._getIndex(keyIndex, valueIndex);
return (this._bitmap[wordIndex] & 1 << bitIndex) > 0;
},
_getIndex: function(keyIndex, valueIndex) {
// find the logical index in the sequence of bits laid out in row major format
// 0 1 2 3 ... maxValueCount-1
// 0 1 2 3 ... maxValueCount-1
// ...
// is laid out as
// 0 1 2 3 ... maxValueCount-1 0 1 2 3 ... maxValueCount-1 ...
const logicalIndex = this._maxValueCount * keyIndex + valueIndex;
// find the 32 bit word where the logical index falls, where only 31 bits in each are used
const wordIndex = Math.floor(logicalIndex / 31);
// inside the 32 bit word, map the bit to the bit going from the
// order least significant bit to most significant bit
// so that bitwise operation can be performed using 1 <<< X
const bitIndex = 30 - logicalIndex % 31; // since only 31 bits are used
return [wordIndex, bitIndex];
},
type: 'MembershipInMemoryCache'
};
Sys ID
22f87224ff032110468365d7d3b8fee6