-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Anyway to save SQL DB to IndexedDB without calling export() for persistence? #302
Comments
I'm also interested in this. Anyone have an idea what the barriers to implementation might be? I'm not familiar with sql.js but I'd be interested in using it if this problem can be sorted out. If someone could give me a heads up as to the what they think might be the best route for fixing this, I'd probably take a swing at it. Cheers! |
Yes, or should not be too hard to implement this feature using https://emscripten.org/docs/api_reference/Filesystem-API.html If you are ready to work on a PR, I can assign you to this, @theSherwood ! |
I can give it a try. Just a heads up: I'm well outside my wheelhouse here. Maybe we should talk design. What kind of granularity would be right? Would every row in sqlLite be a document in IndexedDB? That sounds like the best way to reduce write volume for a database that needs to be persisted frequently. But to my mind, it also means coopting the @lovasoa, what are your thoughts on this? How would you go about it? |
We should just use IDBFS from emscripten; you can read the documentation I linked to in my previous message. It shouldn't be hard to implement. We could simply add an optional |
Maybe I'm misunderstanding the way IDBFS works. Does it save each file as a separate document in IndexedDB? Or does it handle chunking out of the box? |
no, it does not chunk files. see https://github.com/emscripten-core/emscripten/blob/master/src/library_idbfs.js |
Then if sql.js is treating the entire database as a single file, won't that defeat the purpose? It sounds like IDBFS would take the database and save it as a single document, which can also simply be done by using |
no, you are getting it right |
But how can that be done incrementally so as to not be saving the entire database to indexedDB at once, but only updating the records that changed and persisting each row in the sql.js database as a document in indexedDB? Do you have any idea on an approach for that? |
This would be much more complex to implement. In practice, exporting the whole database and persisting it never takes more than a few seconds for huge databases, and it can be done in the background. Did you find a case where persisting the database faster would have a positive impact on the user ? |
i agree with lovasoa its probably not feasible to re-invent new mechanism to persist individual sqlite-records to indexeddb. what we really need are native file-api's like "seek" exposed in browser to exploit sqlite's native file-persistence mechanism (like wal). it appears google is working on nativeio filesystem for browsers @ https://github.com/fivedots/nativeio-explainer. they have an experimental sqlite-wasm implementation @ https://github.com/jabolopes/sqlite-wasm i managed to compile the demo @ https://kaizhu256.github.io/sqlite-wasm/dist/index.html, but couldn't get the nativeio benchmark working. |
@lovasoa The application I have in mind would be attempting to backup user-generated changes almost constantly so as to prevent the user from losing any work. A few seconds for each backup could be problematic. @kaizhu256 Thanks for the links. I'll be sure to keep on eye on that! |
This means users would lose at most a few seconds of work, if their database were really huge. Would that be a problem? |
Probably not a big problem initially, no. I don't want the user to have to think about any of that. So it isn't ideal, but not a huge problem. |
The largest sqlite db I've managed to persist in indexeddb is ~235mb. Chrome doesn't allow indexeddb objects larger than that. For applications with many persisting writes, I had to redesign db and break large tables into smaller 5mb tables that could be quickly persisted as individual indexeddb blobs. |
I'd like to do this because I cannot rely on I'm guessing I would need to specify IDBFS at compile time https://emscripten.org/docs/api_reference/Filesystem-API.html#file-systems with
Do I need to do any additional steps in my code to write to IDB? There's some talk of |
So I think I have it working insofar that it is writing to indexedDB, but without any actual files yet. I'm invoking this using: FS.mkdir("/idb");
FS.mount(IDBFS, {}, "/idb");
FS.syncfs(true, function(err) { ... }); // load from indexeddb
// time goes by...
FS.syncfs(false, function(err) { ... }); // save to indexeddb As per the docs for
I can't use if (root && FS.root) {
throw new FS.ErrnoError(10);
} Trying to unmount results in if (!FS.isMountpoint(lookup.node)) {
throw new FS.ErrnoError(28);
} So I'm a little stuck atm. I think I need to be mounted at this.filename = "dbfile_" + (0xffffffff * Math.random() >>> 0);
if (data != null) {
FS.createDataFile("/", this.filename, data, true, true);
} I think staticInit:function() {
FS.ensureErrnoError();
FS.nameTable = new Array(4096);
FS.mount(MEMFS, {}, '/');
FS.createDefaultDirectories();
FS.createDefaultDevices();
FS.createSpecialDirectories();
FS.filesystems = {
'MEMFS': MEMFS,
'IDBFS': IDBFS,
};
} |
So it seems mounting straight to
This indicates that other filesystems were probably not designed to be mounted at |
Curious if anyone's tackled this again. In #397 it looks like the consensus was to use export(), but tell it to just flush cache without closing the DB. #400 seems to relate to SQLite knowing it's storing data in memory or storing on disk (filesystem) when told to do an export(), with the last comment on Jul 16th. With my DB size over 400MB, chunking is necessary in my case. Has there been any other progress in this area? (chunking & saving to indexedDB, or saving via a filesystem) |
chrome-canary recently shipped with experimental native-filesystem support for webassembly (with database use-case specifically in mind). they have a tutorial to compile wasm's with native-filesystem-support here. note there's some conflict between chrome's experimental feature and w3c's competing file-system-access standard [1], [2]. |
Unfortunately the suitability of the File System Access API for SQLite seems to be going nowhere, despite its recent support in Safari. First of all, Firefox seems pretty strongly opposed to it. In addition, it looks like Chrome's implementation for writes copies the file, writes to the copy, scans the copy for malware, and renames the copy over the original. So changing 1 block of a 1GB SQLite database might cost over 2GB of I/O (1 for the copy, 1 for the scan) unless your filesystem has some kind of block-level deduplication. That's probably worse than export(). Not sure what Safari does. |
Have a look at https://github.com/jlongster/absurd-sql, it uses indexedDb as a file system for sqlite |
Also @jlongster has forked SQL.js to add the supported hooks to allow for custom filesystems. Would be great to see these incorporated into SQL.js mainline. EDIT: didn't see there is already a PR #481 |
I am also having the same requirement. Any suggestion? What approach should I take? |
https://github.com/rhashimoto/wa-sqlite seems to have support for this :) |
I am currently having to call export every time I need to save to indexedDB for persistence. The problem is export greatly increases the save time taken and I cannot save just the SQLJS object due to the new SQL.database constructor not being able to handle that? Is there any way around this or could this be a possible enhancement.
The text was updated successfully, but these errors were encountered: