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