Skip to content
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

[kvdb-web] indexeddb implementation #202

Merged
merged 27 commits into from
Sep 25, 2019
Merged

[kvdb-web] indexeddb implementation #202

merged 27 commits into from
Sep 25, 2019

Conversation

ordian
Copy link
Member

@ordian ordian commented Aug 15, 2019

This is an alternative implementation for #182 based on IndexedDB (cc @tomaka).
Writes data both into memory and IndexedDB, reads from the IndexedDB on open.

Closes #182.

}

// TODO: is it safe for IdbDatabase?
struct MakeSendSync<T>(T);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally use SendWrapper from here: https://docs.rs/send_wrapper/0.2.0/send_wrapper/
As far as I know, it is unfortunately actually not safe to implement Sync. If threads become usable one day, that will bite us.

Copy link
Member Author

@ordian ordian Aug 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is technically unsafe unless we only write in a single thread. I'm not sure what's the best way forward though, this Send + Sync requirement is enforced by the KeyValueDB trait.

kvdb-web/Cargo.toml Outdated Show resolved Hide resolved
.expect_throw("IndexDB should be supported in your browser");

// TODO: don't hardcode version
let open_request = indexed_db.open_with_u32(name, /* version */ 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are only two ways to handle this "version" thing here IMO: either we use the version, by passing it as parameter and adding a method to retrieve it later, or we don't pass any version at all.
I would go for no version at all.

Suggested change
let open_request = indexed_db.open_with_u32(name, /* version */ 1)
let open_request = indexed_db.open_with_u32(name)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, if we reopen the database with more columns that it was opened previously, it will panic on open, when trying to create a transaction to read from a new column. Because a new column is expected to be created on version upgrade (try_create_object_stores).

We can pass the number of columns as a version, sounds reasonable?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it possible to dynamically check the number of columns, and add the missing ones?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried that, but creating a column only possible onupgradeneeded:

The createObjectStore() method of the IDBDatabase interface creates and returns a new object store or index.
this method can be called only within a versionchange transaction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see! Then bump the version if we detect that the number of columns is different?
It might seem stupid, but I'd prefer to use things as they are intended to be used. In other words, the "version" should actually be a version and not a way for us to store a number.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then bump the version if we detect that the number of columns is different?

The version is bumped only when we open the db with a higher version. And we can query the version on after either the open requests succeeds or onupgradeneeded is called (we specified a higher version that it is).

So I went with "by passing it as parameter and adding a method to retrieve it later" approach.

Copy link
Contributor

@tomaka tomaka Sep 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I went with "by passing it as parameter and adding a method to retrieve it later" approach.

What worries me is that nobody is probably ever going to use this mechanism.
RocksDB automatically updates the number of columns if it doesn't match the number on disk, and I'm not sure it's a good idea to force users to manage a database version number just for IndexedDB.

What is going to happen in practice is that people will constantly forget to bump the database version number. RocksDB will work just fine, so nobody will realize, but IndexedDB will break.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In parity-ethereum we have a separate version file stored for RocksDB, see https://github.com/paritytech/parity-ethereum/blob/master/parity/db/rocksdb/migration.rs and the it refuses to open the newer version.

We could open the latest version of the db, see the version and the number of columns, and if the we need more columns, close it and reopen with a different number of version. But that sounds like a hack.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I've implemented this hacky solution.

kvdb-web/src/indexed_db.rs Outdated Show resolved Hide resolved
kvdb-web/src/indexed_db.rs Outdated Show resolved Hide resolved
kvdb-web/src/indexed_db.rs Outdated Show resolved Hide resolved
ordian and others added 13 commits September 5, 2019 16:16
* master:
  [plain_hasher] Migrate to 2018 edition (#213)
  [ethbloom] Improve ethbloom (#215)
  [rlp] fix nested unbounded lists (#203)
  stabilize parity-bytes in no_std environment (#212)
  Speed up hex serialization, support Serde `with`, and fix warnings (#208)
  [ethbloom, ethereum-types,kvdb] migrate to 2018 edition (#205)
  Introduce `ContractAddress` newtype instead of scheme enum (#200)
* master:
  [triehash] Migrate to 2018 edition (#214)
  [rlp] Add no_std support  (#206)
* master:
  Bump version (#219)
  Find PendingIterator in Transaction Pool (#218)
  Modified AsRef impl for U-type macros (#196)
Copy link
Contributor

@tomaka tomaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The version hack is obviously not great, but it's the least bad solution IMO.

@tomaka
Copy link
Contributor

tomaka commented Sep 23, 2019

What's the next step? Does that need another review or can we merge?

@ordian
Copy link
Member Author

ordian commented Sep 23, 2019

It needs another review.

@ordian ordian requested a review from dvdplm September 23, 2019 09:36
Copy link
Contributor

@dvdplm dvdplm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nits and a few more tests would be good, but otherwise lgtm.

kvdb-web/src/indexed_db.rs Outdated Show resolved Hide resolved
kvdb-web/src/lib.rs Outdated Show resolved Hide resolved
kvdb-web/src/lib.rs Show resolved Hide resolved
kvdb-web/src/lib.rs Outdated Show resolved Hide resolved
kvdb-web/src/lib.rs Show resolved Hide resolved
@dvdplm
Copy link
Contributor

dvdplm commented Sep 24, 2019

Running wasm-pack test --headless --firefox on a mac yields:

output div contained:
    Loading scripts...

driver status: signal: 9
driver stdout:
    1569333767372	mozrunner::runner	INFO	Running command: "/Applications/Firefox.app/Contents/MacOS/firefox-bin" "-marionette" "-headless" "-foreground" "-no-remote" "-profile" "/var/folders/vh/svxftrqj1d583q97kl6ghqlh0000gn/T/rust_mozprofile.mak2ynYfurmW"
    1569333768042	Marionette	INFO	Enabled via --marionette
    1569333769292	Marionette	INFO	Listening on port 25808
    *** UTM:SVC TimerManager:registerTimer called after profile-before-change notification. Ignoring timer registration for id: telemetry_modules_ping

driver stderr:
    *** You are running in headless mode.
    2019-09-24 16:02:48.961 plugin-container[96640:19245410] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0xb53b, name = 'com.apple.tsm.portname'
    See /usr/include/servers/bootstrap_defs.h for the error codes.
    2019-09-24 16:02:49.249 plugin-container[96640:19245410] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0xa7b, name = 'com.apple.coredrag'
    See /usr/include/servers/bootstrap_defs.h for the error codes.
    2019-09-24 16:02:49.261 plugin-container[96640:19245410] unable to obtain configuration from file:///Library/Preferences/com.apple.ViewBridge.plist due to Error Domain=NSCocoaErrorDomain Code=257 "The file “com.apple.ViewBridge.plist” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/Library/Preferences/com.apple.ViewBridge.plist, NSUnderlyingError=0x116321f10 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
    2019-09-24 16:02:49.263 plugin-container[96640:19245412] +[NSXPCSharedListener endpointForReply:withListenerName:]: an error occurred while attempting to obtain endpoint for listener 'ClientCallsAuxiliary': Connection invalid
    2019-09-24 16:02:49.888 plugin-container[96641:19245540] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0xaf3b, name = 'com.apple.tsm.portname'
    See /usr/include/servers/bootstrap_defs.h for the error codes.
    2019-09-24 16:02:50.039 plugin-container[96641:19245540] *** CFMessagePort: bootstrap_register(): failed 1100 (0x44c) 'Permission denied', port = 0xaf2b, name = 'com.apple.coredrag'
    See /usr/include/servers/bootstrap_defs.h for the error codes.
    2019-09-24 16:02:50.054 plugin-container[96641:19245540] unable to obtain configuration from file:///Library/Preferences/com.apple.ViewBridge.plist due to Error Domain=NSCocoaErrorDomain Code=257 "The file “com.apple.ViewBridge.plist” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/Library/Preferences/com.apple.ViewBridge.plist, NSUnderlyingError=0x1131380a0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
    2019-09-24 16:02:50.056 plugin-container[96641:19245542] +[NSXPCSharedListener endpointForReply:withListenerName:]: an error occurred while attempting to obtain endpoint for listener 'ClientCallsAuxiliary': Connection invalid

error: some tests failed
error: test failed, to rerun pass '--test indexed_db'
Error: Running Wasm tests with wasm-bindgen-test failed
Caused by: failed to execute `cargo test`: exited with exit code: 1

Using Chrome also fails with:

$ wasm-pack test --headless --chrome
[INFO]: 🎯  Checking for the Wasm target...
    Finished dev [unoptimized + debuginfo] target(s) in 0.11s
[INFO]: ⬇️  Installing wasm-bindgen...
    Finished dev [unoptimized + debuginfo] target(s) in 0.11s
     Running /Users/dvd/dev/parity/parity-common/target/wasm32-unknown-unknown/debug/deps/kvdb_web-8a0ae45a97d7609e.wasm
no tests to run!
     Running /Users/dvd/dev/parity/parity-common/target/wasm32-unknown-unknown/debug/deps/indexed_db-008424fae5ecf423.wasm
Running headless tests in Chrome with `/Users/dvd/Library/Caches/.wasm-pack/chromedriver-b5d7e439698af816/chromedriver`
driver status: signal: 9
driver stdout:
    Starting ChromeDriver 2.46.628411 (3324f4c8be9ff2f70a05a30ebc72ffb013e1a71e) on port 25869
    Only local connections are allowed.
    Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

error: failed to find element reference in response
error: test failed, to rerun pass '--test indexed_db'
Error: Running Wasm tests with wasm-bindgen-test failed
Caused by: failed to execute `cargo test`: exited with exit code: 1

@ordian
Copy link
Member Author

ordian commented Sep 24, 2019

Not sure what to do with macOS, seems like wasm-pack issue to me.

@dvdplm
Copy link
Contributor

dvdplm commented Sep 24, 2019

Not sure what to do with macOS, seems like wasm-pack issue to me.

Ok, sounds like we should perhaps add a README where we list what combinations are "known good" (linux + chrome + ff I guess?) and call it a day? I mean, it doesn't seem like it should block the PR. An issue on the webpack repo linked from the README maybe?

kvdb-web/src/lib.rs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add an implementation of kvdb on top of IndexedDB
3 participants