MOBILE-3977 core: Optimize wscache table
parent
a65919debc
commit
7a1dfa38bd
|
@ -41,6 +41,7 @@ import { CoreLogger } from '@singletons/logger';
|
|||
import { Translate } from '@singletons';
|
||||
import { CoreIonLoadingElement } from './ion-loading';
|
||||
import { CoreLang } from '@services/lang';
|
||||
import { CoreSites } from '@services/sites';
|
||||
|
||||
/**
|
||||
* QR Code type enumeration.
|
||||
|
@ -920,20 +921,20 @@ export class CoreSite {
|
|||
preSets: CoreSiteWSPreSets,
|
||||
emergency?: boolean,
|
||||
): Promise<T> {
|
||||
const db = this.db;
|
||||
if (!db || !preSets.getFromCache) {
|
||||
if (!this.db || !preSets.getFromCache) {
|
||||
throw new CoreError('Get from cache is disabled.');
|
||||
}
|
||||
|
||||
const id = this.getCacheId(method, data);
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
let entry: CoreSiteWSCacheRecord | undefined;
|
||||
|
||||
if (preSets.getCacheUsingCacheKey || (emergency && preSets.getEmergencyCacheUsingCacheKey)) {
|
||||
const entries = await db.getRecords<CoreSiteWSCacheRecord>(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey });
|
||||
const entries = await cacheTable.all({ key: preSets.cacheKey });
|
||||
|
||||
if (!entries.length) {
|
||||
// Cache key not found, get by params sent.
|
||||
entry = await db.getRecord(CoreSite.WS_CACHE_TABLE, { id });
|
||||
entry = await cacheTable.findByPrimaryKey({ id });
|
||||
} else {
|
||||
if (entries.length > 1) {
|
||||
// More than one entry found. Search the one with same ID as this call.
|
||||
|
@ -945,7 +946,7 @@ export class CoreSite {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
entry = await db.getRecord(CoreSite.WS_CACHE_TABLE, { id });
|
||||
entry = await cacheTable.findByPrimaryKey({ id });
|
||||
}
|
||||
|
||||
if (entry === undefined) {
|
||||
|
@ -990,18 +991,25 @@ export class CoreSite {
|
|||
*/
|
||||
async getComponentCacheSize(component: string, componentId?: number): Promise<number> {
|
||||
const params: Array<string | number> = [component];
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
let extraClause = '';
|
||||
if (componentId !== undefined && componentId !== null) {
|
||||
params.push(componentId);
|
||||
extraClause = ' AND componentId = ?';
|
||||
}
|
||||
|
||||
const size = <number> await this.getDb().getFieldSql(
|
||||
'SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE + ' WHERE component = ?' + extraClause,
|
||||
params,
|
||||
return cacheTable.reduce(
|
||||
{
|
||||
sql: 'SUM(length(data))',
|
||||
js: (size, record) => size + record.data.length,
|
||||
jsInitialValue: 0,
|
||||
},
|
||||
{
|
||||
sql: 'WHERE component = ?' + extraClause,
|
||||
sqlParams: params,
|
||||
js: record => record.component === component && (params.length === 1 || record.componentId === componentId),
|
||||
},
|
||||
);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1015,10 +1023,6 @@ export class CoreSite {
|
|||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
protected async saveToCache(method: string, data: any, response: any, preSets: CoreSiteWSPreSets): Promise<void> {
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized.');
|
||||
}
|
||||
|
||||
if (preSets.uniqueCacheKey) {
|
||||
// Cache key must be unique, delete all entries with same cache key.
|
||||
await CoreUtils.ignoreErrors(this.deleteFromCache(method, data, preSets, true));
|
||||
|
@ -1027,6 +1031,7 @@ export class CoreSite {
|
|||
// Since 3.7, the expiration time contains the time the entry is modified instead of the expiration time.
|
||||
// We decided to reuse this field to prevent modifying the database table.
|
||||
const id = this.getCacheId(method, data);
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
const entry = {
|
||||
id,
|
||||
data: JSON.stringify(response),
|
||||
|
@ -1044,7 +1049,7 @@ export class CoreSite {
|
|||
}
|
||||
}
|
||||
|
||||
await this.db.insertRecord(CoreSite.WS_CACHE_TABLE, entry);
|
||||
await cacheTable.insert(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1058,16 +1063,13 @@ export class CoreSite {
|
|||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
protected async deleteFromCache(method: string, data: any, preSets: CoreSiteWSPreSets, allCacheKey?: boolean): Promise<void> {
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized.');
|
||||
}
|
||||
|
||||
const id = this.getCacheId(method, data);
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
if (allCacheKey) {
|
||||
await this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey });
|
||||
await cacheTable.delete({ key: preSets.cacheKey });
|
||||
} else {
|
||||
await this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, { id });
|
||||
await cacheTable.deleteByPrimaryKey({ id });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1084,18 +1086,14 @@ export class CoreSite {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized');
|
||||
}
|
||||
const params = { component };
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
const params = {
|
||||
component,
|
||||
};
|
||||
if (componentId) {
|
||||
params['componentId'] = componentId;
|
||||
}
|
||||
|
||||
await this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, params);
|
||||
await cacheTable.delete(params);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1127,14 +1125,12 @@ export class CoreSite {
|
|||
* @return Promise resolved when the cache entries are invalidated.
|
||||
*/
|
||||
async invalidateWsCache(): Promise<void> {
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized');
|
||||
}
|
||||
|
||||
this.logger.debug('Invalidate all the cache for site: ' + this.id);
|
||||
|
||||
try {
|
||||
await this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 });
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
await cacheTable.update({ expirationTime: 0 });
|
||||
} finally {
|
||||
CoreEvents.trigger(CoreEvents.WS_CACHE_INVALIDATED, {}, this.getId());
|
||||
}
|
||||
|
@ -1147,16 +1143,15 @@ export class CoreSite {
|
|||
* @return Promise resolved when the cache entries are invalidated.
|
||||
*/
|
||||
async invalidateWsCacheForKey(key: string): Promise<void> {
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized');
|
||||
}
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug('Invalidate cache for key: ' + key);
|
||||
|
||||
await this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 }, { key });
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
await cacheTable.update({ expirationTime: 0 }, { key });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1184,18 +1179,19 @@ export class CoreSite {
|
|||
* @return Promise resolved when the cache entries are invalidated.
|
||||
*/
|
||||
async invalidateWsCacheForKeyStartingWith(key: string): Promise<void> {
|
||||
if (!this.db) {
|
||||
throw new CoreError('Site DB not initialized');
|
||||
}
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug('Invalidate cache for key starting with: ' + key);
|
||||
|
||||
const sql = 'UPDATE ' + CoreSite.WS_CACHE_TABLE + ' SET expirationTime=0 WHERE key LIKE ?';
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
await this.db.execute(sql, [key + '%']);
|
||||
await cacheTable.updateWhere({ expirationTime: 0 }, {
|
||||
sql: 'key LIKE ?',
|
||||
sqlParams: [key],
|
||||
js: record => !!record.key?.startsWith(key),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1270,9 +1266,13 @@ export class CoreSite {
|
|||
* @return Promise resolved with the total size of all data in the cache table (bytes)
|
||||
*/
|
||||
async getCacheUsage(): Promise<number> {
|
||||
const size = <number> await this.getDb().getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE);
|
||||
const cacheTable = await CoreSites.getCacheTable(this);
|
||||
|
||||
return size;
|
||||
return cacheTable.reduce({
|
||||
sql: 'SUM(length(data))',
|
||||
js: (size, record) => size + record.data.length,
|
||||
jsInitialValue: 0,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreLang } from '@services/lang';
|
||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreUpdateManager } from '@services/update-manager';
|
||||
|
||||
export default async function(): Promise<void> {
|
||||
await Promise.all([
|
||||
CoreFilepool.initialize(),
|
||||
CoreSites.initialize(),
|
||||
CoreLang.initialize(),
|
||||
CoreLocalNotifications.initialize(),
|
||||
CoreUpdateManager.initialize(),
|
||||
|
|
|
@ -31,6 +31,7 @@ import {
|
|||
CoreSiteConfig,
|
||||
CoreSitePublicConfigResponse,
|
||||
CoreSiteInfoResponse,
|
||||
CoreSiteWSCacheRecord,
|
||||
} from '@classes/site';
|
||||
import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
|
@ -57,6 +58,9 @@ import { CoreErrorWithTitle } from '@classes/errors/errorwithtitle';
|
|||
import { CoreAjaxError } from '@classes/errors/ajaxerror';
|
||||
import { CoreAjaxWSError } from '@classes/errors/ajaxwserror';
|
||||
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreDatabaseTable } from '@classes/database/database-table';
|
||||
import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy';
|
||||
|
||||
export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS');
|
||||
|
||||
|
@ -85,6 +89,7 @@ export class CoreSitesProvider {
|
|||
// Variables for DB.
|
||||
protected appDB: Promise<SQLiteDB>;
|
||||
protected resolveAppDB!: (appDB: SQLiteDB) => void;
|
||||
protected cacheTables: Record<string, CorePromisedValue<CoreDatabaseTable<CoreSiteWSCacheRecord>>> = {};
|
||||
|
||||
constructor(@Optional() @Inject(CORE_SITE_SCHEMAS) siteSchemas: CoreSiteSchema[][] = []) {
|
||||
this.appDB = new Promise(resolve => this.resolveAppDB = resolve);
|
||||
|
@ -99,6 +104,23 @@ export class CoreSitesProvider {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize.
|
||||
*/
|
||||
initialize(): void {
|
||||
CoreEvents.on(CoreEvents.SITE_DELETED, async ({ siteId }) => {
|
||||
if (!siteId || !(siteId in this.cacheTables)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cacheTable = await this.cacheTables[siteId];
|
||||
|
||||
delete this.cacheTables[siteId];
|
||||
|
||||
await cacheTable.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize database.
|
||||
*/
|
||||
|
@ -112,6 +134,33 @@ export class CoreSitesProvider {
|
|||
this.resolveAppDB(CoreApp.getDB());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache table.
|
||||
*
|
||||
* @param siteId Site id.
|
||||
* @returns cache table.
|
||||
*/
|
||||
async getCacheTable(site: CoreSite): Promise<CoreDatabaseTable<CoreSiteWSCacheRecord>> {
|
||||
if (!site.id) {
|
||||
throw new CoreError('Can\'t get cache table for site without id');
|
||||
}
|
||||
|
||||
if (!(site.id in this.cacheTables)) {
|
||||
const promisedTable = this.cacheTables[site.id] = new CorePromisedValue();
|
||||
const table = new CoreDatabaseTableProxy<CoreSiteWSCacheRecord>(
|
||||
{ cachingStrategy: CoreDatabaseCachingStrategy.None },
|
||||
site.getDb(),
|
||||
CoreSite.WS_CACHE_TABLE,
|
||||
);
|
||||
|
||||
await table.initialize();
|
||||
|
||||
promisedTable.resolve(table);
|
||||
}
|
||||
|
||||
return this.cacheTables[site.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the demo data for a certain "name" if it is a demo site.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue