-
Notifications
You must be signed in to change notification settings - Fork 217
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
fix(swingset): update lmdb #5488
Conversation
@@ -88,7 +88,7 @@ while(1) { | |||
processInboundIO(); | |||
const policy = make100CrankPolicy(); | |||
await controller.run(policy); | |||
commit(); | |||
await commit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also update callers of commit()
in packages/solo/src
and packages/cosmic-swingset/src
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They were already await
ing!
Here's what I see missing agoric-sdk/packages/solo/src/start.js Line 251 in 01cdbc9
|
That one is a JSONStore, which is a different API. I'm open to make it apparent async as well for consistency.
This one has already been updated:
|
bcca078
to
8edac53
Compare
@michaelfig I did make it consistent since it didn't really hurt. The only somewhat similar API is now the chain-store, but that one seem to rely on a synchronous |
8edac53
to
35e40e3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good to me, but please get @FUDCo 's approval too, he knows the DB layer much better than me.
} else { | ||
const result = v2.value; | ||
v2 = it2.next(); | ||
/** @type {IteratorResult<any> | null} */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please coordinate with @gibson042 since his #5294 moves this function around.
@@ -198,7 +198,7 @@ function makeJSONStore(dirPath, forceReset = false) { | |||
/** | |||
* Commit unsaved changes. | |||
*/ | |||
function commit() { | |||
async function commit() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be async? This little "json store" doesn't overlap much with the SwingStore, but I suppose if there's any chance of both appearing in the same program, I can see a consistency argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I wasn't sure. Can easily revert this specific commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'm ambivalent.
t.teardown(cleanup); | ||
t.is(isSwingStore(dbDir), false); | ||
const store = initSwingStore(dbDir); | ||
store.kvStore.set('€'.repeat(254), 'Money!'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's assert both sides of the size limit (i.e. assert that 255 3-byte-UTF-8 chars fails), since the success/failure of writes needs to be part of consensus. This isn't an exact constraint (we'd need a mix of encoded sizes, plus a healthy variety of surrogate pairs, to exercise this thoroughly), but I think it's good to be in the habit of knowing what the precise rules are.
I think that means this DB change is consensus-breaking (there are non-trivial unicode strings which would pass the earlier encoding scheme's limit but not the new one, or vice versa), but I'm ok with making that now.. better than later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
255 3-byte-UTF-8 chars fails
It won't fail. The upper limit is actually 1971 bytes I believe.
I think that means this DB change is consensus-breaking
I don't believe so. Nothing is writing large keys since the only user controlled key size is the collections keys which is independently checked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok, so the previous limits were (pardon my js/python pseudocode) str.length < X && len(str.encode('utf-16')) < Y
, and the new limits are str.length < X && len(str.encode('utf-8') < Z
, but for all possible strings, the .length < X
limit (imposed by liveslots) is tighter than the encoded limit (imposed lower down). So landing this can't make any failing userspace behavior start to succeed, or succeeding userspace behavior start to fail.
As long as that criteria is met, I guess we don't need more stringent testing at this layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this test is specifically about checking this assumption. That the worst case str = threeByteUtfChar.repeat(X)
then len(str.encode('utf-8')) < Z
. Aka 3 * X < Z
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor stylistic quibble but aside from that this looks very good. I'm surprised (and happy) that the changes in the underlying LMDB API could be accommodated with such a light touch.
cursor.close(); | ||
/** @type {import("lmdb").RangeOptions} */ | ||
const rangeOptions = {}; | ||
if (start) rangeOptions.start = start; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why our linter didn't pick this up, but please write this as
if (start) {
rangeOptions.start = start;
}
-- always use braces
-- no putting the if consequence on same line as the conditional
Consistent API with swing-store
fa931fe
to
b14cdab
Compare
closes: #5031
best reviewed commit-by-commit
Description
Switches from node-lmdb to lmbd-js which seem more actively maintained. Disable
useWritemap
option which seem to be causing some issues (but not the only cause of them), as it seems no longer necessary.This PR does the minimal amount of code changes in the swingstore by synchronous creating a transaction. This works with the new API because we already ensured that we only ever had one transaction at a time. Once inside a transaction, read after writes are guaranteed to contain the data from the transaction.
However to adapt to the more asynchronous nature of lmdb-js, this PR updates the API of the swingstore to make
commit
andclose
asynchronous. While closing a synchronous transaction is not actually asynchronous, it would be too much of a hack to make it happen synchronously. Since the committers were already all asynchronous, this was a low impact change.lmdb-js
also seem to have a couple differences in behavior, including not passing through themapSize
option or encoding strings (both keys and values) as UTF-8. The former will result in a non preallocated DB file (previously sparse) growing in size with usage. The latter has no practical impact since the LMDB key size was also increased.Drive by fix of
getKeys
iterator interruption which were previously not closing cursors. I've decided to pass errors through, as these really should not happen.Security Considerations
The max key size logic and checks in collections is now no longer matching reality as it assumed a UTF-16 encoding of strings. However since lmdb-js bumps the max key size, it is impossible to generate keys that are too large, and a new test asserts this.
Documentation Considerations
The collections documentation was amended.
Testing Considerations
Fixed some swingstore and swingset tests to handle async commit, and handle parallel execution.
Added a test for lmdb max key size.
Ran a full daily loadgen test on my machine, which used to crash reliably.