1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-24 22:22:08 +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.
- This VFS requires the "semi-fully-sync" FileSystemSyncAccessHandle
(hereafter "SAH") APIs released with Chrome v108. If that API
is not detected, the VFS is not registered.
(hereafter "SAH") APIs released with Chrome v108 (and all other
major browsers released since March 2023). If that API is not
detected, the VFS is not registered.
*/
'use strict';
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
@ -137,11 +138,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xClose: function(pFile){
const pool = getPoolForPFile(pFile);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
if(file) {
try{
pool.log(`xClose ${file.path}`);
pool.setFileForPtr(pFile, false);
pool.mapSFileToOFile(pFile, false);
file.sah.flush();
if(file.flags & capi.SQLITE_OPEN_DELETEONCLOSE){
pool.deletePath(file.path);
@ -162,7 +163,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xFileSize: function(pFile,pSz64){
const pool = getPoolForPFile(pFile);
pool.log(`xFileSize`);
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
const size = file.sah.getSize() - HEADER_OFFSET_DATA;
//log(`xFileSize ${file.path} ${size}`);
wasm.poke64(pSz64, BigInt(size));
@ -172,14 +173,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile);
pool.log(`xLock ${lockType}`);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
file.lockType = lockType;
return 0;
},
xRead: function(pFile,pDest,n,offset64){
const pool = getPoolForPFile(pFile);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
pool.log(`xRead ${file.path} ${n} @ ${offset64}`);
try {
const nRead = file.sah.read(
@ -203,7 +204,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile);
pool.log(`xSync ${flags}`);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
//log(`xSync ${file.path} ${flags}`);
try{
file.sah.flush();
@ -217,7 +218,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const pool = getPoolForPFile(pFile);
pool.log(`xTruncate ${sz64}`);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
//log(`xTruncate ${file.path} ${iSize}`);
try{
file.sah.truncate(HEADER_OFFSET_DATA + Number(sz64));
@ -230,14 +231,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
xUnlock: function(pFile,lockType){
const pool = getPoolForPFile(pFile);
pool.log('xUnlock');
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
file.lockType = lockType;
return 0;
},
xWrite: function(pFile,pSrc,n,offset64){
const pool = getPoolForPFile(pFile);
pool.storeErr();
const file = pool.getFileForPtr(pFile);
const file = pool.getOFileForSFile(pFile);
pool.log(`xWrite ${file.path} ${n} ${offset64}`);
try{
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
// pointer, so map the relevant info we need to that pointer.
const file = {path, flags, sah};
pool.setFileForPtr(pFile, file);
pool.mapSFileToOFile(pFile, file);
file.lockType = capi.SQLITE_LOCK_NONE;
const sq3File = new capi.sqlite3_file(pFile);
sq3File.$pMethods = opfsIoMethods.pointer;
@ -436,6 +437,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
/** Buffer used by [sg]etAssociatedPath(). */
#apBody = new Uint8Array(HEADER_CORPUS_SIZE);
// DataView for this.#apBody
#dvBody;
// associated sqlite3_vfs instance
@ -497,6 +499,11 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
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){
let nRm = 0;
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(){
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
returns it as a two-element Uint32Array.
Computes a digest for the given byte array and returns it as a
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){
let h1 = 0xdeadbeef;
@ -730,14 +741,18 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return rc;
}
getFileForPtr(ptr){
/**
Given an (sqlite3_file*), returns the mapped
xOpen file object.
*/
getOFileForSFile(ptr){
return this.#mapSqlite3FileToFile.get(ptr);
}
/**
Maps or unmaps (if file is falsy) the given (sqlite3_file*)
to an xOpen file object and to this pool object.
*/
setFileForPtr(pFile,file){
mapSFileToOFile(pFile,file){
if(file){
this.#mapSqlite3FileToFile.set(pFile, file);
setPoolForPFile(pFile, this);
@ -746,14 +761,34 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
setPoolForPFile(pFile, false);
}
}
/**
Returns true if the given client-defined file name is in this
object's name-to-SAH map.
*/
hasFilename(name){
return this.#mapFilenameToSAH.has(name)
}
/**
Returns the SAH associated with the given
client-defined file name.
*/
getSAHForPath(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(){
if(!this.#cVfs.pointer) return false;
capi.sqlite3_vfs_unregister(this.#cVfs.pointer);
@ -773,6 +808,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return true;
}
//! Documented elsewhere in this file.
exportFile(name){
const sah = this.#mapFilenameToSAH.get(name) || toss("File not found:",name);
const n = sah.getSize() - HEADER_OFFSET_DATA;
@ -781,6 +817,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return b;
}
//! Documented elsewhere in this file.
importDb(name, bytes){
const n = bytes.byteLength;
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
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. */
#p;
@ -818,18 +857,14 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
this.vfsName = sahPool.vfsName;
}
async addCapacity(n){
return this.#p.addCapacity(n);
}
async reduceCapacity(n){
return this.#p.reduceCapacity(n);
}
getCapacity(){
return this.#p.getCapacity(this.#p);
}
getFileCount(){
return this.#p.getFileCount();
}
async addCapacity(n){ return this.#p.addCapacity(n) }
async reduceCapacity(n){ return this.#p.reduceCapacity(n) }
getCapacity(){ return this.#p.getCapacity(this.#p) }
getFileCount(){ return this.#p.getFileCount() }
async reserveMinimumCapacity(min){
const c = this.#p.getCapacity();
return (c < min) ? this.#p.addCapacity(min - c) : c;
@ -839,20 +874,17 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
importDb(name, bytes){ return this.#p.importDb(name,bytes) }
async wipeFiles(){return this.#p.reset(true)}
async wipeFiles(){ return this.#p.reset(true) }
unlink(filename){
return this.#p.deletePath(filename);
}
unlink(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,
else reject the promise. Returns true on success,
throws on error.
Returns a resolved Promise if the current environment
has a "fully-sync" SAH impl, else a rejected Promise.
*/
const apiVersionCheck = async ()=>{
const dh = await navigator.storage.getDirectory();
@ -1087,7 +1119,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
return thePool.isReady.then(async()=>{
/** The poolUtil object will be the result of the
resolved Promise. */
const poolUtil = new SAHPoolUtil(thePool);
const poolUtil = new OpfsSAHPoolUtil(thePool);
if(sqlite3.oo1){
const oo1 = sqlite3.oo1;

View File

@ -1,5 +1,5 @@
C Update\sthe\sdevelopment-over-ssh\sdocs\sfor\sthe\swasm\sbuild.
D 2023-07-19T17:46:28.936
C More\sinternal\srefactoring\sand\sdocs\sfor\sopfs-sahpool.
D 2023-07-19T17:47:02.768
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
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-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
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-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
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.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 534481cd0c2e6f62dd0a82f25d4b78fdcc671eb70d6966693c98212a6420891c
R 3098985ac29097adbc0d24d2b5daf2dc
P 500109bd0a4c134b91c37f397ff1ee828e09c17f7ecd153f975ede748caee7bb
R 44dc85544ec440f7c21f7b899d57ed02
U stephan
Z 78455e14df71dd2dbc1be007d9b53932
Z e1c9bd04ae7a0c44d52816708800bbbb
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
500109bd0a4c134b91c37f397ff1ee828e09c17f7ecd153f975ede748caee7bb
64ccf6177a019eab46fb3345ad1e8ba80eaf2c9da55767031f9f04ccd16afb4d