-
Notifications
You must be signed in to change notification settings - Fork 0
/
memcache-test.js
210 lines (169 loc) · 6.3 KB
/
memcache-test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// import { v4 as uuidv4 } from 'uuid';
/**
* A class representing an in-memory cache with a size limit.
*/
class MemoryCache {
/**
* Constructs a new MemoryCache object with a specified size limit.
* @param {number} sizeInMB - The size limit of the cache in megabytes (default is 5MB).
*/
constructor(sizeInMB = 5, ) {
this.cache = {};
this._localStorageSize = sizeInMB * 1024 * 1024; // 5MB
this._localStorageSize = sizeInMB * 1024; // 1KB for testing
this._spaceUsed = 0;
this.id = null;
}
setID(id) {
this.id = id;
}
/**
* Retrieves an item from the cache with the specified key.
* @param {string} key - The key of the item to retrieve.
* @returns {*} The value associated with the key, or undefined if the key does not exist.
* @throws {Error} If the key does not exist in the cache.
*/
getItem(key) {
if (!(key in this.cache)) {
throw new Error(`Key '${key}' not found in cache.`);
}
return JSON.parse(this.cache[key]);
}
/**
* Adds an item to the cache with the specified key and value.
* @param {string} key - The key under which to store the value.
* @param {*} value - The value to be stored in the cache.
* @throws {Error} If the cache size limit would be exceeded by adding the new item.
*/
setItem(key, value) {
if (!(key && value)) {
throw new Error("The key or value cannot be empty!!")
}
if (this.spaceUsed + estimateObjectSize(value) > this.localStorageSize) {
throw new Error("Cache size limit exceeded. Unable to add item.");
}
if (this.id === null) {
throw new Error("There is no ID associated with the cache. Set an ID before setting an item");
}
// Add item to cache
this.cache[key] = JSON.stringify(value);
this._spaceUsed += estimateObjectSize(value);
}
/**
* Removes the item with the specified key from the cache.
* @param {string} key - The key of the item to remove from the cache.
* @throws {Error} If the key does not exist in the cache.
*/
removeItem(key) {
if (!(key in this.cache)) {
throw new Error(`Key '${key}' not found in cache. Unable to remove.`);
}
// Remove item from cache
const removedItemSize = estimateObjectSize(this.cache[key]);
delete this.cache[key];
this._returnRemovedItemSpace(removedItemSize);
}
removeTableItemByIndex(index, tableToRemeove) {
if (!Array.isArray(tableToRemeove)) {
throw new Error("The tableToRemove is not an Array");
}
if (tableToRemeove.length === 0) {
return;
}
const entry = tableToRemeove[index];
if (!entry) {
return 0;
}
// Check if the parent id matches this meme cache otherwise the table doesn't belong to memeCache
if (entry.parentID !== this.id) {
throw new Error("The table entry doesn't belong to parent cache")
}
this._returnRemovedItemSpace(entry);
tableToRemeove.splice(index, 1); // Remove the entry from table
}
_returnRemovedItemSpace(entry) {
const size = estimateObjectSize(entry);
this._spaceUsed -= size; // Add the size of the object back to space used
}
/**
* Sets the size limit of the cache.
* @param {number} sizeInMB - The new size limit of the cache in megabytes.
* @throws {Error} If the specified size is not a valid number or exceeds the maximum size limit.
*/
setSize(sizeInMB) {
if (typeof sizeInMB !== "number" || !Number.isInteger(sizeInMB)) {
throw new Error("The size limit must be an integer number in megabytes");
}
if (sizeInMB <= 0) {
throw new Error("The size limit must be a positive number");
}
// if (sizeInMB > this._localStorageSize / (1024 * 1024)) {
// throw new Error("The size limit cannot exceed the maximum limit of 5MB");
// }
if (sizeInMB > this._localStorageSize / (1024)) {
throw new Error("The size limit cannot exceed the maximum limit of 5MB");
}
// this._localStorageSize = sizeInMB * 1024 * 1024;
this._localStorageSize = sizeInMB * 1024;
}
/**
* Retrieves the current availabe space of the cache in bytes.
* @returns {number} The current size of the cache in bytes.
*/
get availableSpace() {
return this._localStorageSize - this._spaceUsed;
}
get spaceUsed() {
return this._spaceUsed;
}
get localStorageSize() {
return this._localStorageSize;
}
/**
* Retrieves the current available space of the cache in MB.
* @returns {number} The current size of the cache in megabytes.
*/
toMB() {
const MB = 1024
return this.availableSpace / (MB * MB)
}
}
/**
* Estimates the size of a list of objects in bytes.
* @param {Array} list - The list of objects to estimate the size of.
* @returns {number} The estimated size of the list in bytes.
*/
function estimateListSize(elemArray) {
console.log(typeof elemArray);
if (elemArray.length === 0) {
return 0;
}
let totalSize = 0;
elemArray.forEach(item => {
totalSize += this._estimateObjectSize(item);
});
return totalSize;
}
/**
* Estimates the size of an object in bytes by converting it to a JSON string.
* @param {Object} obj - The object to estimate the size of.
* @returns {number} The estimated size of the object in bytes, or -1 if an error occurs.
*/
function estimateObjectSize(obj) {
try {
if (!obj) {
return 0;
}
const jsonString = JSON.stringify(obj);
const sizeInBytes = new Blob([jsonString]).size;
return sizeInBytes;
} catch (error) {
console.error("Error estimating object size:", error);
return -1; // Return -1 to indicate an error
}
}
export {
MemoryCache,
estimateListSize,
estimateObjectSize
};