UNPKG

13.6 kBJavaScriptView Raw
1/*
2 * Copyright 2017-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
5 * the License. A copy of the License is located at
6 *
7 * http://aws.amazon.com/apache2.0/
8 *
9 * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11 * and limitations under the License.
12 */
13var __extends = (this && this.__extends) || (function () {
14 var extendStatics = function (d, b) {
15 extendStatics = Object.setPrototypeOf ||
16 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
17 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
18 return extendStatics(d, b);
19 };
20 return function (d, b) {
21 extendStatics(d, b);
22 function __() { this.constructor = d; }
23 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
24 };
25})();
26var __values = (this && this.__values) || function(o) {
27 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
28 if (m) return m.call(o);
29 if (o && typeof o.length === "number") return {
30 next: function () {
31 if (o && i >= o.length) o = void 0;
32 return { value: o && o[i++], done: !o };
33 }
34 };
35 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
36};
37import { CacheList, defaultConfig, getCurrTime, CacheObject } from './Utils';
38import { StorageCache } from './StorageCache';
39import { ConsoleLogger as Logger } from '@aws-amplify/core';
40var logger = new Logger('InMemoryCache');
41/**
42 * Customized in-memory cache with LRU implemented
43 * @member cacheObj - object which store items
44 * @member cacheList - list of keys in the cache with LRU
45 * @member curSizeInBytes - current size of the cache
46 * @member maxPriority - max of the priority
47 * @member cacheSizeLimit - the limit of cache size
48 */
49var InMemoryCacheClass = /** @class */ (function (_super) {
50 __extends(InMemoryCacheClass, _super);
51 /**
52 * initialize the cache
53 *
54 * @param config - the configuration of the cache
55 */
56 function InMemoryCacheClass(config) {
57 var _this = this;
58 var cacheConfig = config
59 ? Object.assign({}, defaultConfig, config)
60 : defaultConfig;
61 _this = _super.call(this, cacheConfig) || this;
62 logger.debug('now we start!');
63 _this.cacheList = [];
64 _this.curSizeInBytes = 0;
65 _this.maxPriority = 5;
66 _this.getItem = _this.getItem.bind(_this);
67 _this.setItem = _this.setItem.bind(_this);
68 _this.removeItem = _this.removeItem.bind(_this);
69 // initialize list for every priority
70 for (var i = 0; i < _this.maxPriority; i += 1) {
71 _this.cacheList[i] = new CacheList();
72 }
73 return _this;
74 }
75 /**
76 * decrease current size of the cache
77 *
78 * @param amount - the amount of the cache size which needs to be decreased
79 */
80 InMemoryCacheClass.prototype._decreaseCurSizeInBytes = function (amount) {
81 this.curSizeInBytes -= amount;
82 };
83 /**
84 * increase current size of the cache
85 *
86 * @param amount - the amount of the cache szie which need to be increased
87 */
88 InMemoryCacheClass.prototype._increaseCurSizeInBytes = function (amount) {
89 this.curSizeInBytes += amount;
90 };
91 /**
92 * check whether item is expired
93 *
94 * @param key - the key of the item
95 *
96 * @return true if the item is expired.
97 */
98 InMemoryCacheClass.prototype._isExpired = function (key) {
99 var text = CacheObject.getItem(key);
100 var item = JSON.parse(text);
101 if (getCurrTime() >= item.expires) {
102 return true;
103 }
104 return false;
105 };
106 /**
107 * delete item from cache
108 *
109 * @param prefixedKey - the key of the item
110 * @param listIdx - indicates which cache list the key belongs to
111 */
112 InMemoryCacheClass.prototype._removeItem = function (prefixedKey, listIdx) {
113 // delete the key from the list
114 this.cacheList[listIdx].removeItem(prefixedKey);
115 // decrease the current size of the cache
116 this._decreaseCurSizeInBytes(JSON.parse(CacheObject.getItem(prefixedKey)).byteSize);
117 // finally remove the item from memory
118 CacheObject.removeItem(prefixedKey);
119 };
120 /**
121 * put item into cache
122 *
123 * @param prefixedKey - the key of the item
124 * @param itemData - the value of the item
125 * @param itemSizeInBytes - the byte size of the item
126 * @param listIdx - indicates which cache list the key belongs to
127 */
128 InMemoryCacheClass.prototype._setItem = function (prefixedKey, item, listIdx) {
129 // insert the key into the list
130 this.cacheList[listIdx].insertItem(prefixedKey);
131 // increase the current size of the cache
132 this._increaseCurSizeInBytes(item.byteSize);
133 // finally add the item into memory
134 CacheObject.setItem(prefixedKey, JSON.stringify(item));
135 };
136 /**
137 * see whether cache is full
138 *
139 * @param itemSize
140 *
141 * @return true if cache is full
142 */
143 InMemoryCacheClass.prototype._isCacheFull = function (itemSize) {
144 return this.curSizeInBytes + itemSize > this.config.capacityInBytes;
145 };
146 /**
147 * check whether the cache contains the key
148 *
149 * @param key
150 */
151 InMemoryCacheClass.prototype.containsKey = function (key) {
152 var prefixedKey = this.config.keyPrefix + key;
153 for (var i = 0; i < this.maxPriority; i += 1) {
154 if (this.cacheList[i].containsKey(prefixedKey)) {
155 return i + 1;
156 }
157 }
158 return -1;
159 };
160 /**
161 * * Set item into cache. You can put number, string, boolean or object.
162 * The cache will first check whether has the same key.
163 * If it has, it will delete the old item and then put the new item in
164 * The cache will pop out items if it is full
165 * You can specify the cache item options. The cache will abort and output a warning:
166 * If the key is invalid
167 * If the size of the item exceeds itemMaxSize.
168 * If the value is undefined
169 * If incorrect cache item configuration
170 * If error happened with browser storage
171 *
172 * @param key - the key of the item
173 * @param value - the value of the item
174 * @param options - optional, the specified meta-data
175 *
176 * @throws if the item is too big which exceeds the limit of single item size
177 * @throws if the key is invalid
178 */
179 InMemoryCacheClass.prototype.setItem = function (key, value, options) {
180 var prefixedKey = this.config.keyPrefix + key;
181 // invalid keys
182 if (prefixedKey === this.config.keyPrefix ||
183 prefixedKey === this.cacheCurSizeKey) {
184 logger.warn("Invalid key: should not be empty or 'CurSize'");
185 return;
186 }
187 if (typeof value === 'undefined') {
188 logger.warn("The value of item should not be undefined!");
189 return;
190 }
191 var cacheItemOptions = {
192 priority: options && options.priority !== undefined
193 ? options.priority
194 : this.config.defaultPriority,
195 expires: options && options.expires !== undefined
196 ? options.expires
197 : this.config.defaultTTL + getCurrTime(),
198 };
199 if (cacheItemOptions.priority < 1 || cacheItemOptions.priority > 5) {
200 logger.warn("Invalid parameter: priority due to out or range. It should be within 1 and 5.");
201 return;
202 }
203 var item = this.fillCacheItem(prefixedKey, value, cacheItemOptions);
204 // check wether this item is too big;
205 if (item.byteSize > this.config.itemMaxSize) {
206 logger.warn("Item with key: " + key + " you are trying to put into is too big!");
207 return;
208 }
209 // if key already in the cache, then delete it.
210 var presentKeyPrio = this.containsKey(key);
211 if (presentKeyPrio !== -1) {
212 this._removeItem(prefixedKey, presentKeyPrio - 1);
213 }
214 // pop out items in the cache when cache is full based on LRU
215 // first start from lowest priority cache list
216 var cacheListIdx = this.maxPriority - 1;
217 while (this._isCacheFull(item.byteSize) && cacheListIdx >= 0) {
218 if (!this.cacheList[cacheListIdx].isEmpty()) {
219 var popedItemKey = this.cacheList[cacheListIdx].getLastItem();
220 this._removeItem(popedItemKey, cacheListIdx);
221 }
222 else {
223 cacheListIdx -= 1;
224 }
225 }
226 this._setItem(prefixedKey, item, Number(item.priority) - 1);
227 };
228 /**
229 * Get item from cache. It will return null if item doesn’t exist or it has been expired.
230 * If you specified callback function in the options,
231 * then the function will be executed if no such item in the cache
232 * and finally put the return value into cache.
233 * Please make sure the callback function will return the value you want to put into the cache.
234 * The cache will abort output a warning:
235 * If the key is invalid
236 *
237 * @param key - the key of the item
238 * @param options - the options of callback function
239 */
240 InMemoryCacheClass.prototype.getItem = function (key, options) {
241 var ret = null;
242 var prefixedKey = this.config.keyPrefix + key;
243 if (prefixedKey === this.config.keyPrefix ||
244 prefixedKey === this.cacheCurSizeKey) {
245 logger.warn("Invalid key: should not be empty or 'CurSize'");
246 return null;
247 }
248 // check whether it's in the cachelist
249 var presentKeyPrio = this.containsKey(key);
250 if (presentKeyPrio !== -1) {
251 if (this._isExpired(prefixedKey)) {
252 // if expired, remove that item and return null
253 this._removeItem(prefixedKey, presentKeyPrio - 1);
254 }
255 else {
256 // if not expired, great, return the value and refresh it
257 ret = CacheObject.getItem(prefixedKey);
258 var item = JSON.parse(ret);
259 this.cacheList[item.priority - 1].refresh(prefixedKey);
260 return item.data;
261 }
262 }
263 if (options && options.callback !== undefined) {
264 var val = options.callback();
265 if (val !== null) {
266 this.setItem(key, val, options);
267 }
268 return val;
269 }
270 return null;
271 };
272 /**
273 * remove item from the cache
274 *
275 * @param key - the key of the item
276 */
277 InMemoryCacheClass.prototype.removeItem = function (key) {
278 var prefixedKey = this.config.keyPrefix + key;
279 // check if the key is in the cache
280 var presentKeyPrio = this.containsKey(key);
281 if (presentKeyPrio !== -1) {
282 this._removeItem(prefixedKey, presentKeyPrio - 1);
283 }
284 };
285 /**
286 * clear the entire cache
287 */
288 InMemoryCacheClass.prototype.clear = function () {
289 var e_1, _a;
290 for (var i = 0; i < this.maxPriority; i += 1) {
291 try {
292 for (var _b = (e_1 = void 0, __values(this.cacheList[i].getKeys())), _c = _b.next(); !_c.done; _c = _b.next()) {
293 var key = _c.value;
294 this._removeItem(key, i);
295 }
296 }
297 catch (e_1_1) { e_1 = { error: e_1_1 }; }
298 finally {
299 try {
300 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
301 }
302 finally { if (e_1) throw e_1.error; }
303 }
304 }
305 };
306 /**
307 * Return all the keys in the cache.
308 */
309 InMemoryCacheClass.prototype.getAllKeys = function () {
310 var e_2, _a;
311 var keys = [];
312 for (var i = 0; i < this.maxPriority; i += 1) {
313 try {
314 for (var _b = (e_2 = void 0, __values(this.cacheList[i].getKeys())), _c = _b.next(); !_c.done; _c = _b.next()) {
315 var key = _c.value;
316 keys.push(key.substring(this.config.keyPrefix.length));
317 }
318 }
319 catch (e_2_1) { e_2 = { error: e_2_1 }; }
320 finally {
321 try {
322 if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
323 }
324 finally { if (e_2) throw e_2.error; }
325 }
326 }
327 return keys;
328 };
329 /**
330 * return the current size of the cache
331 *
332 * @return the current size of the cache
333 */
334 InMemoryCacheClass.prototype.getCacheCurSize = function () {
335 return this.curSizeInBytes;
336 };
337 /**
338 * Return a new instance of cache with customized configuration.
339 * @param config - the customized configuration
340 */
341 InMemoryCacheClass.prototype.createInstance = function (config) {
342 return new InMemoryCacheClass(config);
343 };
344 return InMemoryCacheClass;
345}(StorageCache));
346export { InMemoryCacheClass };
347export var InMemoryCache = new InMemoryCacheClass();
348/**
349 * @deprecated use named import
350 */
351export default InMemoryCache;
352//# sourceMappingURL=InMemoryCache.js.map
\No newline at end of file