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

CAT Part 1: assemble subcomponents: cache's, store and request manager #941

Merged
merged 7 commits into from
Jan 30, 2023

Conversation

cmwaters
Copy link
Contributor

ref: #935

@evan-forbes evan-forbes requested review from a team, mojtaba-esk and rootulp and removed request for a team and mojtaba-esk January 16, 2023 14:46
evan-forbes
evan-forbes previously approved these changes Jan 17, 2023
Copy link
Member

@evan-forbes evan-forbes left a comment

Choose a reason for hiding this comment

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

only had one question beyond that of what was already covered in #935

I still like the separate cache for evictions a lot 🤷 lol

mempool/cat/cache.go Outdated Show resolved Hide resolved
mempool/cat/cache_test.go Outdated Show resolved Hide resolved
mempool/cat/peers.go Outdated Show resolved Hide resolved
evan-forbes
evan-forbes previously approved these changes Jan 19, 2023
Copy link
Contributor

@staheri14 staheri14 left a comment

Choose a reason for hiding this comment

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

I am currently going through some of the pull requests that are related to my upcoming tasks, to familiarize myself with the codebase. I'm not able to give a detailed review at this time, as I am still gathering more information and background. I'll make some non-critical suggestions and comments as I read through the code. :)

The PR looks good to me!

mempool/cat/cache.go Show resolved Hide resolved
mempool/cat/cache.go Show resolved Hide resolved
mempool/cat/cache.go Outdated Show resolved Hide resolved
mempool/cat/cache.go Outdated Show resolved Hide resolved
mempool/cat/cache.go Outdated Show resolved Hide resolved
func NewEvictedTxCache(size int) *EvictedTxCache {
return &EvictedTxCache{
staticSize: size,
cache: make(map[types.TxKey]*EvictedTxInfo),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please explain why don't we allocate the cache size according to the supplied size? similar to what is done for the LRUTxCache.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good point. I will add the capacity.

Note that the capacity should be size + 1 because we add before running the check to evict the last element.

We could also do the same thing as the other cache and add a list here to avoid needing to run a for loop over all items whenever we need to evict but this is not on the hot path so I don't think the tradeoff makes sense.

Copy link
Contributor

@staheri14 staheri14 Jan 20, 2023

Choose a reason for hiding this comment

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

We could also do the same thing as the other cache and add a list here to avoid needing to run a for loop over all items whenever we need to evict but this is not on the hot path so I don't think the tradeoff makes sense.

If the cache becomes full, then this linear search i.e., the loop takes place for every push operation, and the performance degradation MAY be noticeable. However, it depends on how frequent elements are pushed to the EvictedTxCache as well as the cache size.

Copy link
Contributor

Choose a reason for hiding this comment

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

Btw, I am not suggesting to implement the cache optimization in this PR :) , just something to have in mind for the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah it seemed apparent from the initial design of the priority mempool that eviction performance wasn't an important characteristic. For example, you may notice that for eviction, the mempool also perform a sort.Slice on ALL txs currently in the mempool to know which transactions have the lowest priority and should therefore be evicted.

We have metrics tracking the number of evicted transactions so we can track how frequent this occurs and if it becomes a problem in the future, then we can modify these parts

Copy link
Contributor

Choose a reason for hiding this comment

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

We have metrics tracking the number of evicted transactions so we can track how frequent this occurs and if it becomes a problem in the future, then we can modify these parts

That would be helpful.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest creating a GH issue (if we don't have one already) to keep track of any performance improvements we come across for our future reference.

mempool/cat/peers.go Outdated Show resolved Hide resolved
mempool/cat/peers.go Outdated Show resolved Hide resolved
}

type timestampedPeerSet struct {
peers map[uint16]bool
Copy link
Contributor

Choose a reason for hiding this comment

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

The uint16 value maps to the index of a peer in the peerMap field of a mempoolIDs, right? If we could use the p2p.ID instead (as it seems to uniquely identify a peer),then we could avoid situations where there are two entires for the same peer in the peer set e.g., the connection of a peer drops and it re-connects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should just clean up all ephemeral peer data like this whenever the connection drops.

If reconnection was a common occurrence we could look into keeping the mapping around for a period after the connection closed and thus giving the peer the same uint16 if it were to reconnect.

Copy link
Contributor

Choose a reason for hiding this comment

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

We should just clean up all ephemeral peer data like this whenever the connection drops.

Right

If reconnection was a common occurrence we could look into keeping the mapping around for a period after the connection closed and thus giving the peer the same uint16 if it were to reconnect.

This works too, just need an extra book keeping for the index <> p2p.ID mapping (compared to using just p2p.ID and no index)

@rootulp rootulp removed their request for review January 23, 2023 19:05
mempool/cat/cache.go Outdated Show resolved Hide resolved
Copy link
Member

@evan-forbes evan-forbes left a comment

Choose a reason for hiding this comment

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

👍 👍

Copy link
Contributor

@staheri14 staheri14 left a comment

Choose a reason for hiding this comment

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

I've added some final comments and suggestions, but nothing that should hold up the merge process. It looks good to go from my end!

mempool/cat/cache.go Show resolved Hide resolved
Comment on lines +16 to +22
staticSize int

mtx tmsync.Mutex
// cacheMap is used as a quick look up table
cacheMap map[types.TxKey]*list.Element
// list is a doubly linked list used to capture the FIFO nature of the cache
list *list.List
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 based on a similar separation in other structs in this PR, the immutability is an agreement but is not enforceable. If that is the case, then I'd suggest making it explicit in the struct description as well:

Suggested change
staticSize int
mtx tmsync.Mutex
// cacheMap is used as a quick look up table
cacheMap map[types.TxKey]*list.Element
// list is a doubly linked list used to capture the FIFO nature of the cache
list *list.List
// these fields are immutable
staticSize int
// these fields are protected by the mutex
mtx tmsync.Mutex
// cacheMap is used as a quick look up table
cacheMap map[types.TxKey]*list.Element
// list is a doubly linked list used to capture the FIFO nature of the cache
list *list.List

// simple, thread-safe in memory store for transactions
type store struct {
mtx sync.RWMutex
bytes int64
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
bytes int64
bytes int64 // size of store in bytes

Comment on lines +30 to +35
if tx, exists := s.txs[wtx.key]; !exists || tx.height == -1 {
s.txs[wtx.key] = wtx
s.bytes += wtx.size()
return true
}
return false
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a suggestion, as a best practice in Go, it's generally considered a good idea to not have extra indentation in the "happy path" of your code. It's not a blocking issue though!

Suggested change
if tx, exists := s.txs[wtx.key]; !exists || tx.height == -1 {
s.txs[wtx.key] = wtx
s.bytes += wtx.size()
return true
}
return false
tx, exists := s.txs[wtx.key]
if exists && tx.height != -1 {
return false
}
s.txs[wtx.key] = wtx
s.bytes += wtx.size()
return true
}

}

func (s *store) set(wtx *wrappedTx) bool {
if wtx == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if the nil value is something we're expecting or if it might be indicating an error in the state of the calling function. If it's an error, it might be helpful to not silence it and instead return an error message along with the bool so the calling function knows exactly what's going on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that's a good point. I think it's just a defensive thing but you're right that if it did happen for some reason it would go undetected. Perhaps it's better if we panic.

@cmwaters
Copy link
Contributor Author

I'm going to merge this now and will address some of the minor comments in the next PR.

@cmwaters cmwaters merged commit 71c72b8 into v0.34.x-celestia Jan 30, 2023
@cmwaters cmwaters deleted the cal/cat-part-1 branch January 30, 2023 09:54
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.

4 participants