1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-26 09:41:10 +03:00

More internal refactoring and docs for opfs-sahpool.

FossilOrigin-Name: 64ccf6177a019eab46fb3345ad1e8ba80eaf2c9da55767031f9f04ccd16afb4d
This commit is contained in:
stephan
2023-07-19 17:47:02 +00:00
parent 96cb7007a9
commit 55f318e53f
3 changed files with 81 additions and 49 deletions

View File

@ -48,8 +48,9 @@
incompatible with that VFS. incompatible with that VFS.
- This VFS requires the "semi-fully-sync" FileSystemSyncAccessHandle - This VFS requires the "semi-fully-sync" FileSystemSyncAccessHandle
(hereafter "SAH") APIs released with Chrome v108. If that API (hereafter "SAH") APIs released with Chrome v108 (and all other
is not detected, the VFS is not registered. major browsers released since March 2023). If that API is not
detected, the VFS is not registered.
*/ */
'use strict'; 'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
@ -137,11 +138,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xClose: function(pFile){ xClose: function(pFile){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
if(file) { if(file) {
try{ try{
pool.log(`xClose ${file.path}`); pool.log(`xClose ${file.path}`);
pool.setFileForPtr(pFile, false); pool.mapSFileToOFile(pFile, false);
file.sah.flush(); file.sah.flush();
if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){ if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){
pool.deletePath(file.path); pool.deletePath(file.path);
@ -162,7 +163,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xFileSize: function(pFile,pSz64){ xFileSize: function(pFile,pSz64){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.log(`xFileSize`); pool.log(`xFileSize`);
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
const size = file.sah.getSize() - HEADER_OFFSET_DATA; const size = file.sah.getSize() - HEADER_OFFSET_DATA;
//log(`xFileSize ${file.path} ${size}`); //log(`xFileSize ${file.path} ${size}`);
wasm.poke64(pSz64, BigInt(size)); wasm.poke64(pSz64, BigInt(size));
@ -172,14 +173,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.log(`xLock ${lockType}`); pool.log(`xLock ${lockType}`);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
file.lockType = lockType; file.lockType = lockType;
return 0; return 0;
}, },
xRead: function(pFile,pDest,n,offset64){ xRead: function(pFile,pDest,n,offset64){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
pool.log(`xRead ${file.path} ${n} @ ${offset64}`); pool.log(`xRead ${file.path} ${n} @ ${offset64}`);
try { try {
const nRead = file.sah.read( const nRead = file.sah.read(
@ -203,7 +204,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.log(`xSync ${flags}`); pool.log(`xSync ${flags}`);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
//log(`xSync ${file.path} ${flags}`); //log(`xSync ${file.path} ${flags}`);
try{ try{
file.sah.flush(); file.sah.flush();
@ -217,7 +218,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.log(`xTruncate ${sz64}`); pool.log(`xTruncate ${sz64}`);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
//log(`xTruncate ${file.path} ${iSize}`); //log(`xTruncate ${file.path} ${iSize}`);
try{ try{
file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64)); file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64));
@ -230,14 +231,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xUnlock: function(pFile,lockType){ xUnlock: function(pFile,lockType){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.log('xUnlock'); pool.log('xUnlock');
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
file.lockType = lockType; file.lockType = lockType;
return 0; return 0;
}, },
xWrite: function(pFile,pSrc,n,offset64){ xWrite: function(pFile,pSrc,n,offset64){
const pool = getPoolForPFile(pFile); const pool = getPoolForPFile(pFile);
pool.storeErr(); pool.storeErr();
const file = pool.getFileForPtr(pFile); const file = pool.getOFileForSFile(pFile);
pool.log(`xWrite ${file.path} ${n} ${offset64}`); pool.log(`xWrite ${file.path} ${n} ${offset64}`);
try{ try{
const nBytes = file.sah.write( const nBytes = file.sah.write(
@ -349,7 +350,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
// Subsequent I/O methods are only passed the sqlite3_file // Subsequent I/O methods are only passed the sqlite3_file
// pointer, so map the relevant info we need to that pointer. // pointer, so map the relevant info we need to that pointer.
const file = {path, flags, sah}; const file = {path, flags, sah};
pool.setFileForPtr(pFile, file); pool.mapSFileToOFile(pFile, file);
file.lockType = capi.SQLITE_LOCK_NONE; file.lockType = capi.SQLITE_LOCK_NONE;
const sq3File = new capi.sqlite3_file(pFile); const sq3File = new capi.sqlite3_file(pFile);
sq3File.$pMethods = opfsIoMethods.pointer; sq3File.$pMethods = opfsIoMethods.pointer;
@ -436,6 +437,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/** Buffer used by [sg]etAssociatedPath(). */ /** Buffer used by [sg]etAssociatedPath(). */
#apBody = new Uint8Array(HEADER_CORPUS_SIZE); #apBody = new Uint8Array(HEADER_CORPUS_SIZE);
// DataView for this.#apBody
#dvBody; #dvBody;
// associated sqlite3_vfs instance // associated sqlite3_vfs instance
@ -497,6 +499,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return this.getCapacity(); return this.getCapacity();
} }
/**
Reduce capacity by n, but can only reduce up to the limit
of currently-available SAHs. Returns a Promise which resolves
to the number of slots really removed.
*/
async reduceCapacity(n){ async reduceCapacity(n){
let nRm = 0; let nRm = 0;
for(const ah of Array.from(this.#availableSAH)){ for(const ah of Array.from(this.#availableSAH)){
@ -514,7 +521,8 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
/** /**
Releases all currently-opened SAHs. Releases all currently-opened SAHs. The only legal
operation after this is acquireAccessHandles().
*/ */
releaseAccessHandles(){ releaseAccessHandles(){
for(const ah of this.#mapSAHToName.keys()) ah.close(); for(const ah of this.#mapSAHToName.keys()) ah.close();
@ -637,8 +645,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
} }
/** /**
Computes a digest for the given byte array and Computes a digest for the given byte array and returns it as a
returns it as a two-element Uint32Array. two-element Uint32Array. This digest gets stored in the
metadata for each file as a validation check. Changing this
algorithm invalidates all existing databases for this VFS, so
don't do that.
*/ */
computeDigest(byteArray){ computeDigest(byteArray){
let h1 = 0xdeadbeef; let h1 = 0xdeadbeef;
@ -730,14 +741,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc; return rc;
} }
getFileForPtr(ptr){ /**
Given an (sqlite3_file*), returns the mapped
xOpen file object.
*/
getOFileForSFile(ptr){
return this.#mapSqlite3FileToFile.get(ptr); return this.#mapSqlite3FileToFile.get(ptr);
} }
/** /**
Maps or unmaps (if file is falsy) the given (sqlite3_file*) Maps or unmaps (if file is falsy) the given (sqlite3_file*)
to an xOpen file object and to this pool object. to an xOpen file object and to this pool object.
*/ */
setFileForPtr(pFile,file){ mapSFileToOFile(pFile,file){
if(file){ if(file){
this.#mapSqlite3FileToFile.set(pFile, file); this.#mapSqlite3FileToFile.set(pFile, file);
setPoolForPFile(pFile, this); setPoolForPFile(pFile, this);
@ -746,14 +761,34 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
setPoolForPFile(pFile, false); setPoolForPFile(pFile, false);
} }
} }
/**
Returns true if the given client-defined file name is in this
object's name-to-SAH map.
*/
hasFilename(name){ hasFilename(name){
return this.#mapFilenameToSAH.has(name) return this.#mapFilenameToSAH.has(name)
} }
/**
Returns the SAH associated with the given
client-defined file name.
*/
getSAHForPath(path){ getSAHForPath(path){
return this.#mapFilenameToSAH.get(path); return this.#mapFilenameToSAH.get(path);
} }
/**
Removes this object's sqlite3_vfs registration and shuts down
this object, releasing all handles, mappings, and whatnot,
including deleting its data directory. There is currently no
way to "revive" the object and reaquire its resources.
This function is intended primarily for testing.
Resolves to true if it did its job, false if the
VFS has already been shut down.
*/
async removeVfs(){ async removeVfs(){
if(!this.#cVfs.pointer) return false; if(!this.#cVfs.pointer) return false;
capi.sqlite3_vfs_unregister(this.#cVfs.pointer); capi.sqlite3_vfs_unregister(this.#cVfs.pointer);
@ -773,6 +808,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return true; return true;
} }
//! Documented elsewhere in this file.
exportFile(name){ exportFile(name){
const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:",name); const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:",name);
const n = sah.getSize() - HEADER_OFFSET_DATA; const n = sah.getSize() - HEADER_OFFSET_DATA;
@ -781,6 +817,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return b; return b;
} }
//! Documented elsewhere in this file.
importDb(name, bytes){ importDb(name, bytes){
const n = bytes.byteLength; const n = bytes.byteLength;
if(n<512 || n%512!=0){ if(n<512 || n%512!=0){
@ -803,13 +840,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/** /**
A SAHPoolUtil instance is exposed to clients in order to manipulate an OpfsSAHPool object without directly exposing that A OpfsSAHPoolUtil instance is exposed to clients in order to
manipulate an OpfsSAHPool object without directly exposing that
object and allowing for some semantic changes compared to that object and allowing for some semantic changes compared to that
class. class.
Class docs are in the client-level docs for installOpfsSAHPoolVfs(). Class docs are in the client-level docs for
installOpfsSAHPoolVfs().
*/ */
class SAHPoolUtil { class OpfsSAHPoolUtil {
/* This object's associated OpfsSAHPool. */ /* This object's associated OpfsSAHPool. */
#p; #p;
@ -818,18 +857,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
this.vfsName = sahPool.vfsName; this.vfsName = sahPool.vfsName;
} }
async addCapacity(n){ async addCapacity(n){ return this.#p.addCapacity(n) }
return this.#p.addCapacity(n);
} async reduceCapacity(n){ return this.#p.reduceCapacity(n) }
async reduceCapacity(n){
return this.#p.reduceCapacity(n); getCapacity(){ return this.#p.getCapacity(this.#p) }
}
getCapacity(){ getFileCount(){ return this.#p.getFileCount() }
return this.#p.getCapacity(this.#p);
}
getFileCount(){
return this.#p.getFileCount();
}
async reserveMinimumCapacity(min){ async reserveMinimumCapacity(min){
const c = this.#p.getCapacity(); const c = this.#p.getCapacity();
return (c < min) ? this.#p.addCapacity(min - c) : c; return (c < min) ? this.#p.addCapacity(min - c) : c;
@ -841,18 +876,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
async wipeFiles(){ return this.#p.reset(true) } async wipeFiles(){ return this.#p.reset(true) }
unlink(filename){ unlink(filename){ return this.#p.deletePath(filename) }
return this.#p.deletePath(filename);
}
async removeVfs(){ return this.#p.removeVfs() } async removeVfs(){ return this.#p.removeVfs() }
}/* class SAHPoolUtil */; }/* class OpfsSAHPoolUtil */;
/** /**
Ensure that the client has a "fully-sync" SAH impl, Returns a resolved Promise if the current environment
else reject the promise. Returns true on success, has a "fully-sync" SAH impl, else a rejected Promise.
throws on error.
*/ */
const apiVersionCheck = async ()=>{ const apiVersionCheck = async ()=>{
const dh = await navigator.storage.getDirectory(); const dh = await navigator.storage.getDirectory();
@ -1087,7 +1119,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return thePool.isReady.then(async()=>{ return thePool.isReady.then(async()=>{
/** The poolUtil object will be the result of the /** The poolUtil object will be the result of the
resolved Promise. */ resolved Promise. */
const poolUtil = new SAHPoolUtil(thePool); const poolUtil = new OpfsSAHPoolUtil(thePool);
if(sqlite3.oo1){ if(sqlite3.oo1){
const oo1 = sqlite3.oo1; const oo1 = sqlite3.oo1;

View File

@ -1,5 +1,5 @@
C Update\sthe\sdevelopment-over-ssh\sdocs\sfor\sthe\swasm\sbuild. C More\sinternal\srefactoring\sand\sdocs\sfor\sopfs-sahpool.
D 2023-07-19T17:46:28.936 D 2023-07-19T17:47:02.768
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -502,7 +502,7 @@ F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b17386
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89 F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379 F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25 F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.js d3e41757230c8a41fccc4db077d029546f0ebccd13d4ba0111c52ca77779ab70 F ext/wasm/api/sqlite3-vfs-opfs-sahpool.js 05b5646b91faa947833d43a840e8b94abb441afa953ee5a11cc7f07f4e01361a
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 4946af0d6fbd395aa39966562ca85900664605a5f0cc10fff50146dee527812c F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 4946af0d6fbd395aa39966562ca85900664605a5f0cc10fff50146dee527812c
F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
@ -2044,8 +2044,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 534481cd0c2e6f62dd0a82f25d4b78fdcc671eb70d6966693c98212a6420891c P 500109bd0a4c134b91c37f397ff1ee828e09c17f7ecd153f975ede748caee7bb
R 3098985ac29097adbc0d24d2b5daf2dc R 44dc85544ec440f7c21f7b899d57ed02
U stephan U stephan
Z 78455e14df71dd2dbc1be007d9b53932 Z e1c9bd04ae7a0c44d52816708800bbbb
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
500109bd0a4c134b91c37f397ff1ee828e09c17f7ecd153f975ede748caee7bb 64ccf6177a019eab46fb3345ad1e8ba80eaf2c9da55767031f9f04ccd16afb4d