mempool: Separate reactor from implementation#1043
Conversation
This reverts commit d3468a1.
mempool/clist_mempool.go
Outdated
| // Concurrent linked-list of valid txs. | ||
| // `txsMap`: txKey -> CElement is for quick access to txs. | ||
| // Transactions in both `txs` and `txsMap` must to be kept in sync. | ||
| txs *clist.CList |
There was a problem hiding this comment.
When generating documentation from code, it will be confusing if the comment is related to two fields. I suggest commenting both, even if there is some redundancy.
| // Concurrent linked-list of valid txs. | |
| // `txsMap`: txKey -> CElement is for quick access to txs. | |
| // Transactions in both `txs` and `txsMap` must to be kept in sync. | |
| txs *clist.CList | |
| // Concurrent linked-list of valid txs. | |
| // `txs` must to be kept in sync with `txsMap` . | |
| txs *clist.CList | |
| // `txsMap`: txKey -> CElement is for quick access to txs. | |
| // `txsMap` must to be kept in sync with `txs` . |
cason
left a comment
There was a problem hiding this comment.
I would use here the same arguments I have presented for PR #1010:
#1010 (review)
I think we should define and discuss a new mempool API before implementing the (breaking) changes in multiple PRs.
lasarojc
left a comment
There was a problem hiding this comment.
There seems to be a problem in the loop over the transactions, causing transactions to be skipped and violating the expected delivery order.
PR #1153 adds a test to show the problem and addresses the issue by bring the test for nil back.
Co-authored-by: Lasaro <lasaro@informal.systems>
* Adding a test for when peers are late * passes the test added in the previous commit * passes the test added in the previous commit * Fix iteration and typo * Making the sleep dependendant on a smaller sleep we want to wait for
otrack
left a comment
There was a problem hiding this comment.
I believe that changing CheckTx is necessary. The current interface is not sound: it takes as input a callback cb which will be later called by another callback. This pattern is non-stanadrd and unecessarily complex. Moreover, cb necessarily lives outside of the mempool. This should be avoided because changes against the mempool must be thread safe.
The new interface @hvanz is proposing returns a promise. The promise captures the fact that the side effects of CheckTx are applied asynchronously. This change to the interface is not breaking because mempool#CheckTx is only used internally.
On the other hand, I am not in favor of the introduction of the CListIterator, modifying the way the reactor accesses the mempool. As indicated in my review, this change is not trivial because the underlying list is a non-standard concurrent list. I recommend to add these changes in a different commit with proper testing on them. Even better, before doing that, I recommend to actually model and verify the clist abstraction.
| } | ||
|
|
||
| func (mem *CListMempool) SetTxRemovedCallback(cb func(txKey types.TxKey)) { | ||
| mem.removeTxOnReactorCb = cb |
There was a problem hiding this comment.
This is a very restrictive interface. Add some defensive programming here, by checking it was not set already. Document what is expected. Visibility would be package level (but this does not exist in golang.)
| // Safe for concurrent use by multiple goroutines. | ||
| func (mem *CListMempool) TxsWaitChan() <-chan struct{} { | ||
| return mem.txs.WaitChan() | ||
| func (mem *CListMempool) NewIterator() Iterator { |
There was a problem hiding this comment.
Document this. As above, explain that it is a restricted interface.
| mem.txsMap.Store(memTx.tx.Key(), e) | ||
| atomic.AddInt64(&mem.txsBytes, int64(len(memTx.tx))) | ||
| mem.metrics.TxSizeBytes.Observe(float64(len(memTx.tx))) | ||
| func (mem *CListMempool) addTx(entry *Entry) { |
There was a problem hiding this comment.
Comment this method.
I suggest to pack methods according to their visibility levels, e.g., first public ones then private ones. Mixing things makes understanding the code difficult.
There was a problem hiding this comment.
I agree with sorting the methods by visibility, but this will require to change most of the file, and I don't want to do it in this PR.
| lastElement *clist.CElement // last accessed element in the list | ||
| nextEntryAvailable chan struct{} // channel to communicate that there is at least one entry available | ||
| mtx sync.RWMutex | ||
| } |
There was a problem hiding this comment.
I would move this code to CList.
There is no need to for the iterator to be thread safe. Each peer has its own iterator. Hence, the mtx field can be dropped.
Besides that, I do not understand the logic of the nextEntryAvailable field.
| } | ||
|
|
||
| return iter.lastElement.Value.(*Entry) | ||
| } |
There was a problem hiding this comment.
I am concernend about this set of changes, regarding how the reactor iterates over the mempool. They should be part of a different commit.
Overall, this is non-trivial code. The underlying list is a non-standard concurrent list (not à la M. Scott). As a consequence, we should be very cautious when using it. At the very least, this new way to iterate should be tested in unit tests. I would even recommend to actually model the clist with Quint, before adding an iterator atop it.
|
Depends on #1169 |
|
Closing this PR as it is not clear that the proposed solution is correct. The main change introduced by this PR is an iterator for In the proposed solution, there is an iterator for each peer that reads from |
Closes #1042
Depends on #1010
In
Mempoolinterface:NewIteratorfor iterating the mempool entriesSetLoggerChanges in the mempool reactor:
NewReactornow takes aMempoolinterface as a parameter, instead ofCListMempool,TxsWaitChanandTxsFrontfor iterating throughCListMempool's entries,NextWaitChanandNextfrommempoolTx.PR checklist
.changelog(we use unclog to manage our changelog)docs/orspec/) and code comments