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

R4R: Refactor Iterator Gas Consumption #2357

Merged
merged 9 commits into from
Sep 26, 2018
Merged

Conversation

alexanderbez
Copy link
Contributor

@alexanderbez alexanderbez commented Sep 19, 2018

  • Cleanup gas type and store (godocs, consts, and receivers).
  • Remove gas consumption on gasIterator#Key and gasIterator#Value.
  • Add gas consumption for iterator initialization (gasKVStore#iterator) and gasIterator#Next. Next() include the dynamic cost of the value's length.
    • I chose to set the flat cost for Next() to be the sum of the old flat costs of Key() (5) and Value() (10).

I did not choose to implement UnsafeGetParent as I think that should be a for a separate PR if we so decide to want it.

closes: #2017


  • Targeted PR against correct branch (see CONTRIBUTING.md)

  • Linked to github-issue with discussion and accepted design OR link to spec that describes this work.

  • Wrote tests

  • Updated relevant documentation (docs/)

  • Added entries in PENDING.md with issue #

  • rereviewed Files changed in the github PR explorer


For Admin Use:

  • Added appropriate labels to PR (ex. wip, ready-for-review, docs)
  • Reviewers Assigned
  • Squashed all commits, uses message "Merge pull request #XYZ: [title]" (coding standards)

@alexanderbez alexanderbez changed the title WIP: Refactor Iterator Gas Consumption R4R: Refactor Iterator Gas Consumption Sep 19, 2018
store/gaskvstore.go Outdated Show resolved Hide resolved
Copy link
Contributor

@ValarDragon ValarDragon left a comment

Choose a reason for hiding this comment

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

Is the Gas Iterator based off of the CacheKVStore?

Under the current implementation, iterator creation should be charging n log n in size due to the sorting, and we don't really need to charge for next calls. If we go with the optimizations mentioned in #2286 then we'd have to make inserting into there cost log_2 n, and ignore what I said about n log n. Not sure how to do this without having cache kv store communicate more than whats in the store interface though.

If this is directly going to IAVL, this implementation makes sense.

@alexanderbez
Copy link
Contributor Author

Is the Gas Iterator based off of the CacheKVStore?

Yes, well it can be -- BaseApp calls CacheMultiStore on the commit multi-store, which then a context is created based off of. When KVStore(key) is called, you get a cache-wrapped, gas metering/consuming store.

Under the current implementation, iterator creation should be charging n log n in size due to the sorting, and we don't really need to charge for next calls.

Due to items := ci.dirtyItems(ascending)? True, but can we make assumptions about the gasKVStore's parent?

... we don't really need to charge for next calls.

Why? Ultimately, a DB read could be performed, no?

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Thanks @alexanderbez, see comments.

}
return newGasIterator(gi.gasMeter, gi.gasConfig, parent)

gs.gasMeter.ConsumeGas(gs.gasConfig.IterInitCostFlat, sdk.GasIterInitCostFlatDesc)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think when we call parent.Iterator (or parent.ReverseIterator) it already seeks to the first value, so we should charge key and value cost as with .Next(). I don't know if we need a flat cost but having that too is definitely safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will amend to have initialization incur a cost of akin to .Next() -- this will actually result in the removal of the IterInitCostFlat.

Copy link
Contributor

Choose a reason for hiding this comment

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

also you have to double-check Valid() here and maybe below too before calling .Value()

Copy link
Contributor

Choose a reason for hiding this comment

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

otherwise it will panic!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed.

store/gaskvstore.go Outdated Show resolved Hide resolved
@cwgoes
Copy link
Contributor

cwgoes commented Sep 20, 2018

Is the Gas Iterator based off of the CacheKVStore?

No, the cost model is based off an underlying IAVL tree. I think we can just ignore the cache layer for now, although in the future it would be nice if we could charge less for cacheable reads or repeated writes to the same location.

@ValarDragon
Copy link
Contributor

ValarDragon commented Sep 20, 2018

... we don't really need to charge for next calls.

Why? Ultimately, a DB read could be performed, no?

Iirc, when doing an iterator on a cache kv store, the dirty items are all in memory and sorted. So reading from IAVL isn't happening on next right now if its in the set of things getting sorted, as its already in memory. (Could be wrong, I have not spent that long digging through cache kv store)

No, the cost model is based off an underlying IAVL tree. I think we can just ignore the cache layer for now, although in the future it would be nice if we could charge less for cacheable reads or repeated writes to the same location.

This feels very odd that we're charging for computation thats not happening but your right, thats #postlaunch able. I'll take another look at the PR, what Bez wrote from what I remember is correct with that mindset.

@alexanderbez
Copy link
Contributor Author

alexanderbez commented Sep 20, 2018

Gas gets called on a cacheKVStore from the context. Which returns a gasKVStore who's parent is a cacheKVStore who's parent is a iavlStore. cacheKVStore returns an iterator of type cacheMergeIterator. Which may call Next() on the iavlStore. So a read from disk may happen as I see it. Correct me if I'm wrong.

@codecov
Copy link

codecov bot commented Sep 20, 2018

Codecov Report

❗ No coverage uploaded for pull request base (develop@91cac96). Click here to learn what that means.
The diff coverage is 79.24%.

@@            Coverage Diff            @@
##             develop   #2357   +/-   ##
=========================================
  Coverage           ?     65%           
=========================================
  Files              ?     135           
  Lines              ?    8423           
  Branches           ?       0           
=========================================
  Hits               ?    5475           
  Misses             ?    2587           
  Partials           ?     361

@alexanderbez
Copy link
Contributor Author

Addressed your comments @cwgoes 👍

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

utACK

LGTM but not merging yet so @ValarDragon has another chance to review.

@alexanderbez
Copy link
Contributor Author

@ValarDragon bump.

// No gas costs for deletion
gi.parent.Delete(key)
gs.parent.Delete(key)
Copy link
Contributor

@ValarDragon ValarDragon Sep 25, 2018

Choose a reason for hiding this comment

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

I know you didn't change this, but why is deleting 0 cost? Shouldn't it be at least as complex as Has?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a good observation. We're freeing up space, but I agree it should charge the same price as Has. Thoughts @cwgoes ?

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't charge because space is freed - but actually this might be a DoS vector though, good catch. Let's charge the same as Has.

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

utACK - thanks @alexanderbez

@cwgoes cwgoes merged commit 8ca8acf into develop Sep 26, 2018
@cwgoes cwgoes deleted the bez/2017-gas-iter-refactor branch September 26, 2018 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gas should be charged for Next, rather than Key() and Value()
3 participants