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

Enable collection deletion without swapping in key objects #5641

Merged
merged 1 commit into from
Jul 9, 2022

Conversation

FUDCo
Copy link
Contributor

@FUDCo FUDCo commented Jun 22, 2022

If collection clear is unconditional, allow clearing out the entire contents without deserializing the keys.

Fixes #5053

@FUDCo FUDCo added enhancement New feature or request SwingSet package: SwingSet labels Jun 22, 2022
@FUDCo FUDCo requested a review from warner June 22, 2022 03:47
@FUDCo FUDCo self-assigned this Jun 22, 2022
@FUDCo FUDCo changed the title feat: enable collection deletion without swapping in key objects Enable collection deletion without swapping in key objects Jun 23, 2022
Copy link
Member

@warner warner left a comment

Choose a reason for hiding this comment

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

probably-small changes to make, but looks good overall

packages/SwingSet/src/liveslots/collectionManager.js Outdated Show resolved Hide resolved
}
}
if (!hasWeakKeys) {
syscall.vatstoreSet(prefix('|entryCount'), '0');
Copy link
Member

Choose a reason for hiding this comment

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

This adds a vatstoreSet to the "delete the whole collection" case that wasn't there before, right? That seems like a tiny regression.

What do you think about having the caller (clearInternal) retain responsibility for writing out this length=0, so it can continue to use the same if (!hasWeakKeys && !isDeleting) logic as before? In that case, clearInternal() would do something like:

{
  let doMoreGC = false;
  if (isDeleting || (matchAny(keyPatt) && matchAny(valuePatt))) {
    doMoreGC = clearInternalFull();
  } else {
    for (const k of keys(keyPatt, valuePatt)) {
      doMoreGC = deleteInternal(k) || doMoreGC;
    }
  }
  if (!hasWeakKeys && !isDeleting) {
...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense.

doMoreGC =
value.slots.map(vrm.removeReachableVref).some(b => b) || doMoreGC;
syscall.vatstoreDelete(dbKey);
if (dbKey[0] === 'r') {
Copy link
Member

Choose a reason for hiding this comment

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

This is coupling to the behavior of.. packages/store/src/patterns/encodePassable.js > makeEncodePassable()? I'm a bit nervous about bitrot if store decided to change their encoding scheme.

I obviously don't want to call decodeRemotable() on dbKey, that would defeat the purpose of this fix.

One option would be to create a separate instance of makeDecodePassable() whose only job is to report "reference or not", probably by counting whether the decodeRemotable passed in was called or not:

function dbKeyIsRemotable(dbKey) {
  let isRemotable = false;
  function decodeRemotable(rem) { isRemotable = true; return undefined; }
  const decoder = makeDecodePassable({decodeRemotable});
  decoder(dbKey);
  return isRemotable;
}

Another option is to add a unit test which explicitly checks the output of makeEncodePassable to see that the encoded key starts with 'r', and to add cross-pointing comments between the test and this line (so store ever changes its behavior, our test will fail, and when someone goes to update the test, they'll following the pointer here and update the === 'r' comparison at the same time).

A third option (the most efficient and maintainable) would be to change store to export an additional function like:

export const encodedIsRemotable = (encoded) => encoded[0] === 'r';
harden(encodedIsRemotable);

plus a unit test in store. Not sure what @erights would think about that.

I'm undecided as to which I like better, but I know I want at least one of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My first reaction was that this ship had already sailed, as we have various other code that has baked in understanding of the encoding, but closer inspection suggests that's not so (there is some code like that but it's already inside the store package where it belongs). Of the three options you propose, I think the first is gross and the second is icky, so I lean towards the third. There's already all kinds of other whacky stuff exported from store so I don't expect @erights to object too loudly. In the interest of moving things forward I'm inclined to follow the "ask for forgiveness rather than permission" strategy.

packages/SwingSet/test/gc-helpers.js Outdated Show resolved Hide resolved
@@ -233,12 +233,12 @@ const testUpgrade = async (t, defaultManagerType) => {

for (let i = 1; i < NUM_SENSORS + 1; i += 1) {
const vref = durVref(i);
const impKref = impKrefs[i];
// const impKref = impKrefs[i];
Copy link
Member

Choose a reason for hiding this comment

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

Does the test also pass if you instead just delete the chunk of survivingDurables.push(10); ... above? I tried to arrange the test to let us delete adjustments as we fixed the bugs that necessitated them, and commenting out all of these checks makes the tests less strict than they need to be.

(of course #5636 disables this entire swath of checks, depending upon the order in which they land, but it would be nice if they were as accurate as possible for the day in the future that we reenable them)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. I tried fiddling with the test as you suggest here but either I'm not understand what you're proposing or what you're proposing doesn't work. I don't really understand what this test is actually doing, so...

Unless you have a more concrete thing to try, I'm going to leave this bit as is.

Copy link
Member

Choose a reason for hiding this comment

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

bummer, ok, when you merge this with the #5636 commenting-out, maybe add a comment to the line 266 t.is(reachable, expI) line just saying disabled as part of #5641 so we can backtrack this to the changes that necessitated it

at some point I might try to walk through this test and see how much can be re-enabled

@FUDCo FUDCo force-pushed the 5053-more-efficient-collection-clear branch from eaed688 to 2044afb Compare July 9, 2022 01:38
@FUDCo FUDCo requested a review from warner July 9, 2022 01:39
Copy link
Member

@warner warner left a comment

Choose a reason for hiding this comment

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

looks good!

@@ -233,12 +233,12 @@ const testUpgrade = async (t, defaultManagerType) => {

for (let i = 1; i < NUM_SENSORS + 1; i += 1) {
const vref = durVref(i);
const impKref = impKrefs[i];
// const impKref = impKrefs[i];
Copy link
Member

Choose a reason for hiding this comment

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

bummer, ok, when you merge this with the #5636 commenting-out, maybe add a comment to the line 266 t.is(reachable, expI) line just saying disabled as part of #5641 so we can backtrack this to the changes that necessitated it

at some point I might try to walk through this test and see how much can be re-enabled

@FUDCo FUDCo force-pushed the 5053-more-efficient-collection-clear branch from 2044afb to 8ed6493 Compare July 9, 2022 08:37
@FUDCo FUDCo added the automerge:rebase Automatically rebase updates, then merge label Jul 9, 2022
@mergify mergify bot merged commit 414d49b into master Jul 9, 2022
@mergify mergify bot deleted the 5053-more-efficient-collection-clear branch July 9, 2022 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge enhancement New feature or request SwingSet package: SwingSet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

collection manager clearInternal instantiates keys during deletion
2 participants