Upgrading to the PouchDb indexedDb adapter while testing signals in web workers...

This commit is contained in:
Eric van der Vlist 2023-02-11 11:31:32 +01:00
parent e73497265f
commit 4a4ebdff50
11 changed files with 362 additions and 5 deletions

75
package-lock.json generated
View File

@ -35,6 +35,7 @@
"osmtogeojson": "^3.0.0-beta.5", "osmtogeojson": "^3.0.0-beta.5",
"patch-package": "^6.5.1", "patch-package": "^6.5.1",
"pouchdb": "^8.0.1", "pouchdb": "^8.0.1",
"pouchdb-adapter-indexeddb": "^8.0.1",
"pouchdb-browser": "^8.0.1", "pouchdb-browser": "^8.0.1",
"proj4": "^2.8.1", "proj4": "^2.8.1",
"solid-js": "^1.6.10", "solid-js": "^1.6.10",
@ -7095,6 +7096,40 @@
"vuvuzela": "1.0.3" "vuvuzela": "1.0.3"
} }
}, },
"node_modules/pouchdb-adapter-indexeddb": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-adapter-indexeddb/-/pouchdb-adapter-indexeddb-8.0.1.tgz",
"integrity": "sha512-pX4FdL2isG4uhYXXnBUQJnkwcu+mBUjN/TW+B6aQhU+b/ZpLzH1XU/aui3/X604vhyOwy+DE4MsZEIsohUkR4g==",
"dependencies": {
"pouchdb-adapter-utils": "8.0.1",
"pouchdb-binary-utils": "8.0.1",
"pouchdb-errors": "8.0.1",
"pouchdb-md5": "8.0.1",
"pouchdb-merge": "8.0.1",
"pouchdb-utils": "8.0.1"
}
},
"node_modules/pouchdb-adapter-utils": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-adapter-utils/-/pouchdb-adapter-utils-8.0.1.tgz",
"integrity": "sha512-2nTeYaImu958BU4e46SSdv0IdkXYS/PSy5CXyfb7jK9g0aBAp/JRi7qh9nsTjk4FewpT6OpaE/7evxMQa7UuMg==",
"dependencies": {
"pouchdb-binary-utils": "8.0.1",
"pouchdb-collections": "8.0.1",
"pouchdb-errors": "8.0.1",
"pouchdb-md5": "8.0.1",
"pouchdb-merge": "8.0.1",
"pouchdb-utils": "8.0.1"
}
},
"node_modules/pouchdb-binary-utils": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-binary-utils/-/pouchdb-binary-utils-8.0.1.tgz",
"integrity": "sha512-WsuR/S0aoUlcA0Alt99czkXsfuXWcrYXAcvGiTW02zawVXOafCnb/qHjA09TUaV0oy5HeHmYaNnDckoOUqspeA==",
"dependencies": {
"buffer-from": "1.1.2"
}
},
"node_modules/pouchdb-browser": { "node_modules/pouchdb-browser": {
"version": "8.0.1", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-browser/-/pouchdb-browser-8.0.1.tgz", "resolved": "https://registry.npmjs.org/pouchdb-browser/-/pouchdb-browser-8.0.1.tgz",
@ -7106,6 +7141,46 @@
"vuvuzela": "1.0.3" "vuvuzela": "1.0.3"
} }
}, },
"node_modules/pouchdb-collections": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-collections/-/pouchdb-collections-8.0.1.tgz",
"integrity": "sha512-TlkQ2GGHJApJgL0b7bJMQcwX6eMfVenLeoK9mqHfC2fJssui+HWJJ5LYKHOWan11SeB90BQVFbO6rHN6CJQeDg=="
},
"node_modules/pouchdb-errors": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-errors/-/pouchdb-errors-8.0.1.tgz",
"integrity": "sha512-H+ZsQxcG/JV3Tn29gnM6c9+lRPCN91ZYOkoIICsLjVRYgOTzN1AvNUD/G5JCB+81aI/u3fxZec0LEaZh6g6NHA=="
},
"node_modules/pouchdb-md5": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-md5/-/pouchdb-md5-8.0.1.tgz",
"integrity": "sha512-shVcs/K/iilrcAhDEERpLIrGm/cnDVsXiocOzs7kycJEuBqYnLD9nj58VwWDcum26wfa8T9cznvEGE1jlYVNPQ==",
"dependencies": {
"pouchdb-binary-utils": "8.0.1",
"spark-md5": "3.0.2"
}
},
"node_modules/pouchdb-merge": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-merge/-/pouchdb-merge-8.0.1.tgz",
"integrity": "sha512-79dw6+K7js2+/kt9u4hKOkGCnz+ov0+yft2k21n6M+ylFEQyMKuWHEZRoFWr72o1vxwjhIXhUM1PB2PIdxIh0Q==",
"dependencies": {
"pouchdb-utils": "8.0.1"
}
},
"node_modules/pouchdb-utils": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/pouchdb-utils/-/pouchdb-utils-8.0.1.tgz",
"integrity": "sha512-pWgxdk9EHVWJmjQoEvTe+ZlPXyjcuQ/vgLITN+RjGwcYhoQYUE1M0PksQd2dUP3V8lGS4+wrg9lEM/qSJPYcpw==",
"dependencies": {
"clone-buffer": "1.0.0",
"immediate": "3.3.0",
"pouchdb-collections": "8.0.1",
"pouchdb-errors": "8.0.1",
"pouchdb-md5": "8.0.1",
"uuid": "8.3.2"
}
},
"node_modules/pouchdb/node_modules/isarray": { "node_modules/pouchdb/node_modules/isarray": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",

View File

@ -58,6 +58,7 @@
"osmtogeojson": "^3.0.0-beta.5", "osmtogeojson": "^3.0.0-beta.5",
"patch-package": "^6.5.1", "patch-package": "^6.5.1",
"pouchdb": "^8.0.1", "pouchdb": "^8.0.1",
"pouchdb-adapter-indexeddb": "^8.0.1",
"pouchdb-browser": "^8.0.1", "pouchdb-browser": "^8.0.1",
"proj4": "^2.8.1", "proj4": "^2.8.1",
"solid-js": "^1.6.10", "solid-js": "^1.6.10",

110
src/db-admin/compact.ts Normal file
View File

@ -0,0 +1,110 @@
import { Signal } from 'solid-js';
import PouchDB from 'pouchdb';
import { getSettings } from '../db/settings';
import { delay } from '../lib/delay';
export const compactDb = async (p: { signal: Signal<any>; params: any }) => {
const { signal, params } = p;
const [, setStatus] = signal;
console.log({ caller: 'compactDb', p });
const db = new PouchDB('dyomedea', { auto_compaction: true });
const dbinfo = await db.info();
const tasks = PouchDB.activeTasks.list();
setStatus({ status: 'starting', db: 'dyomedea', dbinfo, tasks });
return;
const timerId = setInterval(async () => {
const dbinfo = await db.info();
const tasks = PouchDB.activeTasks.list();
if (tasks.length > 0) {
setStatus({ status: 'ongoing', db: 'dyomedea', dbinfo, tasks });
} else {
setStatus({ status: 'terminated', db: 'dyomedea', dbinfo, tasks });
clearInterval(timerId);
}
}, 1000);
const openIDb = (name: string) =>
new Promise((resolve, reject) => {
const iDb = indexedDB.open(name);
iDb.onerror = (event: any) => {
console.error({
caller: 'compactDb',
message: 'open db error',
target: event.target,
});
reject(event.target.errorCode);
};
iDb.onsuccess = (event: any) => {
console.log({
caller: 'compactDb',
message: 'open db',
target: event.target,
});
resolve(event.target.result);
};
});
const getAll = (store: any) =>
new Promise((resolve, reject) => {
const request = store.getAll();
request.onerror = (event: any) => {
console.error({
caller: 'compactDb',
message: 'getAll error',
target: event.target,
});
reject(event.target.errorCode);
};
request.onsuccess = (event: any) => {
console.log({
caller: 'compactDb',
message: 'getAll',
target: event.target,
});
resolve(event.target.result as any[]);
};
});
const iDb = (await openIDb('_pouch_dyomedea')) as IDBDatabase;
const bySequence = iDb.transaction('by-sequence', 'readonly');
const store = bySequence.objectStore('by-sequence');
console.log({
caller: 'compactDb',
message: 'transaction opened',
bySequence,
store,
});
const sequences = (await getAll(store)) as any[];
setStatus({
status: 'revisions',
db: 'dyomedea',
sequences,
});
sequences.forEach(async (sequence) => {
const { _deleted, _doc_id_rev } = sequence;
if (_deleted) {
const [id, rev] = _doc_id_rev.split('::');
// const purge = await db.purge(id, rev);
console.log({
caller: 'compactDb',
message: 'purging',
id,
rev,
sequence,
purge,
});
await delay(100);
}
});
// db.compact();
};

View File

@ -4,7 +4,7 @@ import getUri from '../lib/ids';
export const initialAccount = { export const initialAccount = {
id: 'initial', id: 'initial',
name: '???', name: '???',
localDb: 'dyomedea', localDb: '_dyomedea_',
}; };
export const getAccounts = async () => { export const getAccounts = async () => {

View File

@ -1,5 +1,6 @@
import _ from 'lodash'; import _ from 'lodash';
import PouchDB from 'pouchdb'; import PouchDB from 'pouchdb';
import indexeddb from 'pouchdb-adapter-indexeddb';
import uri from '../lib/ids'; import uri from '../lib/ids';
import { toHex } from '../lib/to-hex'; import { toHex } from '../lib/to-hex';
import { import {
@ -11,6 +12,8 @@ import {
import changeHandler from './change-handler'; import changeHandler from './change-handler';
import { getSettings, putSettings } from './settings'; import { getSettings, putSettings } from './settings';
PouchDB.plugin(indexeddb);
const dbDefinitionId = uri('dbdef', {}); const dbDefinitionId = uri('dbdef', {});
const currentDbDefinition = { const currentDbDefinition = {
@ -29,7 +32,8 @@ export const initDb = async (params: any) => {
console.log({ caller: 'initDb' }); console.log({ caller: 'initDb' });
if (globalThis.localDb === undefined) { if (globalThis.localDb === undefined) {
globalThis.localDb = new PouchDB('$local_dyomedea$', { globalThis.localDb = new PouchDB('_local_dyomedea_', {
adapter: 'indexeddb',
auto_compaction: true, auto_compaction: true,
revs_limit: 10, revs_limit: 10,
}); });
@ -55,10 +59,20 @@ export const initDb = async (params: any) => {
if (globalThis.db === undefined) { if (globalThis.db === undefined) {
globalThis.db = new PouchDB(currentAccount.localDb, { globalThis.db = new PouchDB(currentAccount.localDb, {
auto_compaction: false, adapter: 'indexeddb',
auto_compaction: true,
}); });
} }
const db = globalThis.db; const db = globalThis.db;
const dbinfo = await db.info();
// db.compact();
console.log({
caller: 'initDb',
dbinfo,
activeTasks: PouchDB.activeTasks.list(),
storage: await navigator.storage.estimate(),
});
//
var previousDbDefinition = { var previousDbDefinition = {
_id: dbDefinitionId, _id: dbDefinitionId,
type: dbDefinitionId, type: dbDefinitionId,
@ -150,5 +164,11 @@ export const initDb = async (params: any) => {
// changes.cancel(); // changes.cancel();
console.log({
caller: 'initDb (end)',
dbinfo,
activeTasks: PouchDB.activeTasks.list(),
storage: await navigator.storage.estimate(),
});
globalThis.dbReady = true; globalThis.dbReady = true;
}; };

View File

@ -1,7 +1,6 @@
import { cloneDeep, debounce, memoize, property, wrap } from 'lodash'; import { cloneDeep, debounce, memoize, property, wrap } from 'lodash';
import { delay } from '../lib/delay';
import getUri from '../lib/ids'; import getUri from '../lib/ids';
import { appendToArray, putNewGpx } from './gpx'; import { putNewGpx } from './gpx';
import { getFamily, put } from './lib'; import { getFamily, put } from './lib';
export const emptyRte: Rte = { export const emptyRte: Rte = {

View File

@ -10,6 +10,9 @@ import dict from './i18n';
import App from './App'; import App from './App';
import { Language } from '@suid/icons-material'; import { Language } from '@suid/icons-material';
import { createWorkerSignal } from './solid-workers/solid-worker-main';
import { createEffect } from 'solid-js';
import dispatch from './workers/dispatcher-main';
// See https://stackoverflow.com/questions/71538643/property-wakelock-does-not-exist-on-type-navigator // See https://stackoverflow.com/questions/71538643/property-wakelock-does-not-exist-on-type-navigator
const requestWakeLock = async () => { const requestWakeLock = async () => {
@ -55,6 +58,20 @@ const getLanguage = () => {
const i18nDict = createI18nContext(dict, getLanguage()); const i18nDict = createI18nContext(dict, getLanguage());
const settings: any = await dispatch({
action: 'getSettings',
});
const accounts: any = await dispatch({
action: 'getAccounts',
});
const [compactDbStatus] = createWorkerSignal({
provider: 'compactDb',
params: { settings, accounts },
});
createEffect(() => {
console.log({ caller: 'createEffect', compactDbStatus: compactDbStatus() });
});
render( render(
() => ( () => (
<Router> <Router>

2
src/lib/delay.ts Normal file
View File

@ -0,0 +1,2 @@
export const delay = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));

View File

@ -0,0 +1 @@
declare module 'pouchdb-adapter-indexeddb';

View File

@ -0,0 +1,73 @@
import { createSignal, Signal } from 'solid-js';
declare global {
var exportQueue: Map<string, any>;
}
let worker: Worker;
const init = () => {
console.log({ caller: 'solid-worker-main / init' });
globalThis.exportQueue = new Map<
string,
{ count: number; signal: Signal<any> }
>();
worker = new Worker(new URL('./solid-worker', import.meta.url), {
type: 'module',
});
worker.onmessage = (event: any) => {
const { _id, _updatedValue } = event.data;
console.log({
caller: 'solid-worker-main / message received',
_id,
_updatedValue,
});
if (!globalThis.exportQueue.get(_id)) {
console.error({
caller: 'solid-worker-main / message received',
message: 'not found',
_id,
_updatedValue,
});
}
const signal = globalThis.exportQueue.get(_id).signal;
signal[1](_updatedValue);
};
};
export const createWorkerSignal = (parameters: {
provider: string;
params?: any;
initialValue?: any;
}) => {
if (!worker) {
init();
}
const { provider, params, initialValue } = parameters;
const id = JSON.stringify({ provider, params });
if (globalThis.exportQueue.has(id)) {
globalThis.exportQueue.get(id).count++;
return globalThis.exportQueue.get(id).signal;
}
const signal = createSignal(initialValue);
globalThis.exportQueue.set(id, { signal, count: 1 });
worker.postMessage({ ...parameters, _id: id });
return signal;
};
export const releaseWorkerSignal = (parameters: {
provider: string;
params: any;
}) => {
const { provider, params } = parameters;
const id = JSON.stringify({ provider, params });
if (globalThis.exportQueue.has(id)) {
globalThis.exportQueue.get(id).count--;
if (globalThis.exportQueue.get(id).count === 0) {
globalThis.exportQueue.delete(id);
worker.postMessage({ ...parameters, _id: id, _release: true });
}
}
};

View File

@ -0,0 +1,59 @@
import { createEffect, createRoot, createSignal, Signal } from 'solid-js';
import { compactDb } from '../db-admin/compact';
declare global {
var importQueue: Map<string, any>;
}
globalThis.importQueue = new Map<string, Signal<any>>();
const providers = {
compactDb,
};
onmessage = function (e) {
createRoot((dispose) => {
const { provider, params, initialValue, _release, _id } = e.data;
console.log({
caller: 'solid-worker / onmessage',
e,
provider,
params,
initialValue,
_release,
_id,
});
if (_release) {
dispose();
return;
}
if (!Object.hasOwn(providers, provider)) {
console.error({
caller: 'solid-worker',
message: 'Unknown provider',
provider,
});
}
const signal = createSignal(initialValue);
// globalThis.importQueue.set(_id, signal); // Would be needed for bidirectional signals...
createEffect(() => {
console.log({
caller: 'solid_worker / effect',
provider,
params,
initialValue,
_release,
currentValue: signal[0](),
_id,
});
postMessage({ _id, _updatedValue: signal[0]() });
});
const providerFunction = providers[provider as keyof typeof providers];
providerFunction({ params, signal });
});
};