const kvvfsKeyPrefix = (v)=>kvvfsIsPersistentName(v) ? 'kvvfs-'+v+'-' : '';
/**
- Throws if storage name n is not valid for use as a storage name.
- Much of this goes back to kvvfs having a fixed buffer size for
- its keys, and the storage name needing to be encoded in the keys
- for local/session storage. We disallow non-ASCII to avoid
- problems with truncated multibyte characters at the end of the
- key buffer.
+ Throws if storage name n (JS string) is not valid for use as a
+ storage name. Much of this goes back to kvvfs having a fixed
+ buffer size for its keys, and the storage name needing to be
+ encoded in the keys for local/session storage. We disallow
+ non-ASCII to avoid problems with truncated multibyte characters
+ at the end of the key buffer.
The second argument must only be true when called from xOpen() -
it makes names with a "-journal" suffix legal.
let i;
for( i = 0; i < len; ++i ){
const ch = n.codePointAt(i);
- if( ch<45 || ch >126 ){
+ if( ch<43 || ch >126 ){
toss3(capi.SQLITE_RANGE,
"Illegal character ("+ch+"d) in storage name:",n);
}
cache.storagePool[store.jzClass] =
cache.storagePool[store.jzClass+'-journal'] = store;
+ /**
+ The public name of the current thread's transient storage
+ object. A storage object with this name gets preinstalled.
+ */
+ const nameOfThisThreadStorage = '.';
+
/**
Map of JS-stringified KVVfsFile::zClass names to
reference-counted Storage objects. These objects are created in
*/
cache.storagePool = Object.assign(Object.create(null),{
/* Start off with mappings for well-known names. */
- localThread: newStorageObj('localThread')
+ [nameOfThisThreadStorage]: newStorageObj(nameOfThisThreadStorage)
});
if( globalThis.Storage ){
const decodePages = ear.decodePages;
const f = ear.events[eventName];
if( f ){
- if( ear.elideJournal && args[0]==='jrnl' ){
+ if( !ear.includeJournal && args[0]==='jrnl' ){
continue;
}
if( 'write'===eventName && ear.decodePages && +args[0]>0 ){
}
const store = storageForZClass(which);
if( !store ) return 0;
- const keyPrefix = store.keyPrefix;
if( store.files.length ){
toss3(capi.SQLITE_ACCESS,
"Cannot clear in-use database storage.");
for( i = 0; i < n; ++i ){
const k = s.key(i);
//debug("kvvfs_clear ?",k);
- if(!keyPrefix || k.startsWith(keyPrefix)) toRm.push(k);
+ if(!store.keyPrefix || k.startsWith(store.keyPrefix)) toRm.push(k);
}
toRm.forEach((kk)=>s.removeItem(kk));
//alertFilesToReload(store);
});
const pages = Object.create(null);
let xpages;
- const keyPrefix = kvvfsKeyPrefix(rc.name);
+ const keyPrefix = store.keyPrefix;
const rxTail = keyPrefix
? /^kvvfs-[^-]+-(\w+)/ /* X... part of kvvfs-NAME-X... */
: undefined;
requires no extra work, we already have it in hand, and it's
often smaller. It's not great for interchange, though.
- - elideJournal [=false]: if true, writes and deletes of
- "jrnl" records are elided (no event is sent).
+ - includeJournal [=false]: if true, writes and deletes of
+ "jrnl" records are included. If false, no events are sent
+ for journal updates.
- Passing the same object ot sqlite3_js_kvvfs_unlisten() will
+ Passing the same object to sqlite3_js_kvvfs_unlisten() will
remove the listener.
Each one of the events callbacks will be called asynchronously
- 'write' gets a length-two array holding the key and value which
were written. The key is always a string, even if it's a db page
number. For db-page records, the value's type depends on
- opt.decodePages. All others, including the journal, are strings
- (the latter, being in a kvvfs-specific format, is delivered in
- its kvvfs-native format). More details below.
+ opt.decodePages. All others, including the journal, are strings.
+ (The journal, being a kvvfs-specific format, is delivered in
+ that same JSON-friendly format.) More details below.
- 'delete' gets the string-type key of the deleted record.
- - 'sync' receives
- one argument: true if it was triggered by db file's
- xSync(), false if it was triggered by xFileControl() (which
- triggers before the xSync() and also triggers is the DB has
- PRAGMA SYNCHRONOUS=OFF.
+ - 'sync' gets a boolean value: true if it was triggered by db
+ file's xSync(), false if it was triggered by xFileControl(). The
+ latter triggers before the xSync() and also triggers if the DB
+ has PRAGMA SYNCHRONOUS=OFF (in which case xSync() is not
+ triggered).
- The arguments to 'write', and keys to 'delete', are in one of the
- following forms:
+ The key/value arguments to 'write', and key argument to 'delete',
+ are in one of the following forms:
- 'sz' = the unencoded db size as a string. This specific key is
key is never deleted, so is only ever passed to 'write' events.
- 'jrnl' = the current db journal as a kvvfs-encoded string. This
journal format is not useful anywhere except in the kvvfs
- internals. These events are not fired if opt.elideJournal is
- true.
-
- - '[1-9][0-9]*' (a db page number) = a db page. Its type depends
- on opt.decodePages. These may be written and deleted in arbitrary
- order. If a page is deleted, the db is shrinking.
+ internals. These events are not fired if opt.includeJournal is
+ false.
- For 'local' and 'session' storage, all of those keys have a
- prefix of 'kvvfs-local-' resp. 'kvvfs-session-'. This is required
- both for backwards compatibility and to enable dbs in those
- storage objects to coexit with client data. Other storage objects
- do not have a prefix.
+ - '[1-9][0-9]*' (a db page number) = Its type depends on
+ opt.decodePages. These may be written and deleted in arbitrary
+ order.
Design note: JS has StorageEvents but only in the main thread,
which is why the listeners are not based on that.
DB.dbCtorHelper.call(this, opt);
};
sqlite3.oo1.JsStorageDb.defaultStorageName
- = cache.storagePool.session ? 'session' : 'localThread';
+ = cache.storagePool.session ? 'session' : nameOfThisThreadStorage;
const jdb = sqlite3.oo1.JsStorageDb;
jdb.prototype = Object.create(DB.prototype);
jdb.clearStorage = sqlite3_js_kvvfs_clear;
name: 'transient kvvfs',
//predicate: ()=>false,
test: function(sqlite3){
- const filename = 'localThread' /* preinstalled instance */;
+ const filename = '.' /* preinstalled instance */;
const JDb = sqlite3.oo1.JsStorageDb;
const DB = sqlite3.oo1.DB;
pglog.pages = [];
pglog.jrnl = undefined;
pglog.size = undefined;
- pglog.elideJournal = true;
+ pglog.includeJournal = false;
pglog.decodePages = true;
pglog.exception = new Error("Testing that exceptions from listeners do not interfere");
const toss = ()=>{
const listener = {
storage: filename,
reserve: true,
- elideJournal: pglog.elideJournal,
+ includeJournal: pglog.includeJournal,
decodePages: pglog.decodePages,
events: {
'open': (ev)=>{
T.assert('string'===typeof ev.data);
switch(ev.data){
case 'jrnl':
- T.assert(!pglog.elideJournal);
+ T.assert(pglog.includeJournal);
pglog.jrnl = null;
break;
default:{
.assert('string'===typeof key);
switch( key ){
case 'jrnl':
- T.assert(!pglog.elideJournal);
+ T.assert(pglog.includeJournal);
pglog.jrnl = val;
break;
case 'sz':{
debug("kvvfs listener counts:",counts);
T.assert( counts.open );
T.assert( counts.close );
- T.assert( listener.elideJournal ? !counts.delete : counts.delete );
+ T.assert( listener.includeJournal ? counts.delete : !counts.delete );
T.assert( counts.write );
T.assert( counts.xSync );
T.assert( counts.xFileControlSync>=counts.xSync );
T.assert( counts.open===counts.close );
- T.assert( pglog.elideJournal
- ? (undefined===pglog.jrnl)
- : (null===pglog.jrnl),
+ T.assert( pglog.includeJournal
+ ? (null===pglog.jrnl)
+ : (undefined===pglog.jrnl),
"Unexpected pglog.jrnl value: "+pglog.jrnl );
if( 1 ){
T.assert(undefined===pglog.pages[0], "Expecting empty slot 0");
-C Add\ssync\sevents\sto\skvvfs.listen()\sso\sthat\sstreaming\scan\smaybe\sget\sa\sbetter\ssense\sof\swhen\sit's\sokay\sto\sprocess\sthe\sstream.
-D 2025-11-30T07:08:45.236
+C Rename\skvvfs's\s'localThread'\sstorage\sobject\sto\s'.'.\sSwap\skvvfs.listen()'s\selideJournal(=false)\soption\swith\sincludeJournal(=false)\s(i.e.\sopt\sin\sinstead\sof\sopt\sout).
+D 2025-11-30T08:32:52.350
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 9654b565b346dc609b75d15337f20acfa7af7d9d558da1afeb9b6d8eaa404966
F ext/wasm/api/sqlite3-vfs-helper.c-pp.js 3f828cc66758acb40e9c5b4dcfd87fd478a14c8fb7f0630264e6c7fa0e57515d
-F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 92e838b2b1b3039d14ab43f23a99c553df5bd967525457335e2d498f4b72f632
+F ext/wasm/api/sqlite3-vfs-kvvfs.c-pp.js 352436a4e3adf66ae68dcff58ebb5aabe9754d716b818d955bceaf2641b6f815
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js a2eea6442556867b589e04107796c6e1d04a472219529eeb45b7cd221d7d048b
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js 88ce2078267a2d1af57525a32d896295f4a8db7664de0e17e82dc9ff006ed8d3
F ext/wasm/api/sqlite3-vtab-helper.c-pp.js 366596d8ff73d4cefb938bbe95bc839d503c3fab6c8335ce4bf52f0d8a7dee81
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.c-pp.html 0e432ec2c0d99cd470484337066e8d27e7aee4641d97115338f7d962bf7b081a
F ext/wasm/tester1.c-pp.html 52d88fe2c6f21a046030a36410b4839b632f4424028197a45a3d5669ea724ddb
-F ext/wasm/tester1.c-pp.js cb0b1a07bd19af014e62343b973c61be312ef91f612b83db074b1542969d64e3
+F ext/wasm/tester1.c-pp.js d8fb2ae2b3aff305040f595be7e0be0fc14fac510fe8bbc92dbb48af9d124c98
F ext/wasm/tests/opfs/concurrency/index.html 657578a6e9ce1e9b8be951549ed93a6a471f4520a99e5b545928668f4285fb5e
F ext/wasm/tests/opfs/concurrency/test.js d08889a5bb6e61937d0b8cbb78c9efbefbf65ad09f510589c779b7cc6a803a88
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b8fee839b0199d1d2714c99612ea4b4d943d8b0033d742eaa66e1575ce46f0d2
-R fb9f8ede3e2ffe33cbb590ee3d7d0cdc
+P a4b6dadffa1b43aadebfa06a1de14d763efd18b16c4a3e87f1bd039fbff2524d
+R f7259cd8e3b1071dcc04e1dcebc90322
U stephan
-Z a9c442087c9256ab328a4323b6416791
+Z 1f9741d6046d640c682611f3b5f58d30
# Remove this line to create a well-formed Fossil manifest.