Browse Source

feat: revise cache logic

pull/5502/head
Wing-Kam Wong 2 years ago
parent
commit
672501d9ed
  1. 8
      packages/nocodb-nest/src/cache/CacheMgr.ts
  2. 11
      packages/nocodb-nest/src/cache/NocoCache.ts
  3. 34
      packages/nocodb-nest/src/cache/RedisCacheMgr.ts
  4. 36
      packages/nocodb-nest/src/cache/RedisMockCacheMgr.ts

8
packages/nocodb-nest/src/cache/CacheMgr.ts vendored

@ -4,7 +4,13 @@ export default abstract class CacheMgr {
public abstract del(key: string): Promise<any>; public abstract del(key: string): Promise<any>;
public abstract getAll(pattern: string): Promise<any[]>; public abstract getAll(pattern: string): Promise<any[]>;
public abstract delAll(scope: string, pattern: string): Promise<any[]>; public abstract delAll(scope: string, pattern: string): Promise<any[]>;
public abstract getList(scope: string, list: string[]): Promise<any[]>; public abstract getList(
scope: string,
list: string[],
): Promise<{
list: any[];
isNoneList: boolean;
}>;
public abstract setList( public abstract setList(
scope: string, scope: string,
subListKeys: string[], subListKeys: string[],

11
packages/nocodb-nest/src/cache/NocoCache.ts vendored

@ -56,8 +56,15 @@ export default class NocoCache {
public static async getList( public static async getList(
scope: string, scope: string,
subKeys: string[], subKeys: string[],
): Promise<any[]> { ): Promise<{
if (this.cacheDisabled) return Promise.resolve([]); list: any[];
isNoneList: boolean;
}> {
if (this.cacheDisabled)
return Promise.resolve({
list: [],
isNoneList: false,
});
return this.client.getList(scope, subKeys); return this.client.getList(scope, subKeys);
} }

34
packages/nocodb-nest/src/cache/RedisCacheMgr.ts vendored

@ -114,7 +114,13 @@ export default class RedisCacheMgr extends CacheMgr {
); );
} }
async getList(scope: string, subKeys: string[]): Promise<any[]> { async getList(
scope: string,
subKeys: string[],
): Promise<{
list: any[];
isNoneList: boolean;
}> {
// remove null from arrays // remove null from arrays
subKeys = subKeys.filter((k) => k); subKeys = subKeys.filter((k) => k);
// e.g. key = nc:<orgs>:<scope>:<project_id_1>:<base_id_1>:list // e.g. key = nc:<orgs>:<scope>:<project_id_1>:<base_id_1>:list
@ -125,9 +131,21 @@ export default class RedisCacheMgr extends CacheMgr {
// e.g. arr = ["nc:<orgs>:<scope>:<model_id_1>", "nc:<orgs>:<scope>:<model_id_2>"] // e.g. arr = ["nc:<orgs>:<scope>:<model_id_1>", "nc:<orgs>:<scope>:<model_id_2>"]
const arr = (await this.get(key, CacheGetType.TYPE_ARRAY)) || []; const arr = (await this.get(key, CacheGetType.TYPE_ARRAY)) || [];
log(`RedisCacheMgr::getList: getting list with key ${key}`); log(`RedisCacheMgr::getList: getting list with key ${key}`);
return Promise.all( const isNoneList = arr.length && arr[0] === 'NONE';
if (isNoneList) {
return Promise.resolve({
list: [],
isNoneList,
});
}
return {
list: await Promise.all(
arr.map(async (k) => await this.get(k, CacheGetType.TYPE_OBJECT)), arr.map(async (k) => await this.get(k, CacheGetType.TYPE_OBJECT)),
); ),
isNoneList,
};
} }
async setList( async setList(
@ -144,8 +162,8 @@ export default class RedisCacheMgr extends CacheMgr {
? `${this.prefix}:${scope}:list` ? `${this.prefix}:${scope}:list`
: `${this.prefix}:${scope}:${subListKeys.join(':')}:list`; : `${this.prefix}:${scope}:${subListKeys.join(':')}:list`;
if (!list.length) { if (!list.length) {
log(`RedisCacheMgr::setList: List is empty for ${listKey}. Skipping ...`); // Set NONE here so that it won't hit the DB on each page load
return Promise.resolve(true); return this.set(listKey, ['NONE']);
} }
// fetch existing list // fetch existing list
const listOfGetKeys = const listOfGetKeys =
@ -225,7 +243,11 @@ export default class RedisCacheMgr extends CacheMgr {
? `${this.prefix}:${scope}:list` ? `${this.prefix}:${scope}:list`
: `${this.prefix}:${scope}:${subListKeys.join(':')}:list`; : `${this.prefix}:${scope}:${subListKeys.join(':')}:list`;
log(`RedisCacheMgr::appendToList: append key ${key} to ${listKey}`); log(`RedisCacheMgr::appendToList: append key ${key} to ${listKey}`);
const list = (await this.get(listKey, CacheGetType.TYPE_ARRAY)) || []; let list = (await this.get(listKey, CacheGetType.TYPE_ARRAY)) || [];
if (list.length && list[0] === 'NONE') {
list = [];
await this.del(listKey);
}
list.push(key); list.push(key);
return this.set(listKey, list); return this.set(listKey, list);
} }

36
packages/nocodb-nest/src/cache/RedisMockCacheMgr.ts vendored

@ -114,7 +114,13 @@ export default class RedisMockCacheMgr extends CacheMgr {
); );
} }
async getList(scope: string, subKeys: string[]): Promise<any[]> { async getList(
scope: string,
subKeys: string[],
): Promise<{
list: any[];
isNoneList: boolean;
}> {
// remove null from arrays // remove null from arrays
subKeys = subKeys.filter((k) => k); subKeys = subKeys.filter((k) => k);
// e.g. key = nc:<orgs>:<scope>:<project_id_1>:<base_id_1>:list // e.g. key = nc:<orgs>:<scope>:<project_id_1>:<base_id_1>:list
@ -125,9 +131,21 @@ export default class RedisMockCacheMgr extends CacheMgr {
// e.g. arr = ["nc:<orgs>:<scope>:<model_id_1>", "nc:<orgs>:<scope>:<model_id_2>"] // e.g. arr = ["nc:<orgs>:<scope>:<model_id_1>", "nc:<orgs>:<scope>:<model_id_2>"]
const arr = (await this.get(key, CacheGetType.TYPE_ARRAY)) || []; const arr = (await this.get(key, CacheGetType.TYPE_ARRAY)) || [];
log(`RedisMockCacheMgr::getList: getting list with key ${key}`); log(`RedisMockCacheMgr::getList: getting list with key ${key}`);
return Promise.all( const isNoneList = arr.length && arr[0] === 'NONE';
if (isNoneList) {
return Promise.resolve({
list: [],
isNoneList,
});
}
return {
list: await Promise.all(
arr.map(async (k) => await this.get(k, CacheGetType.TYPE_OBJECT)), arr.map(async (k) => await this.get(k, CacheGetType.TYPE_OBJECT)),
); ),
isNoneList,
};
} }
async setList( async setList(
@ -144,10 +162,8 @@ export default class RedisMockCacheMgr extends CacheMgr {
? `${this.prefix}:${scope}:list` ? `${this.prefix}:${scope}:list`
: `${this.prefix}:${scope}:${subListKeys.join(':')}:list`; : `${this.prefix}:${scope}:${subListKeys.join(':')}:list`;
if (!list.length) { if (!list.length) {
log( // Set NONE here so that it won't hit the DB on each page load
`RedisMockCacheMgr::setList: List is empty for ${listKey}. Skipping ...`, return this.set(listKey, ['NONE']);
);
return Promise.resolve(true);
} }
// fetch existing list // fetch existing list
const listOfGetKeys = const listOfGetKeys =
@ -227,7 +243,11 @@ export default class RedisMockCacheMgr extends CacheMgr {
? `${this.prefix}:${scope}:list` ? `${this.prefix}:${scope}:list`
: `${this.prefix}:${scope}:${subListKeys.join(':')}:list`; : `${this.prefix}:${scope}:${subListKeys.join(':')}:list`;
log(`RedisMockCacheMgr::appendToList: append key ${key} to ${listKey}`); log(`RedisMockCacheMgr::appendToList: append key ${key} to ${listKey}`);
const list = (await this.get(listKey, CacheGetType.TYPE_ARRAY)) || []; let list = (await this.get(listKey, CacheGetType.TYPE_ARRAY)) || [];
if (list.length && list[0] === 'NONE') {
list = [];
await this.del(listKey);
}
list.push(key); list.push(key);
return this.set(listKey, list); return this.set(listKey, list);
} }

Loading…
Cancel
Save