-
Notifications
You must be signed in to change notification settings - Fork 770
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
Core/196/handle backlog deletes #337
Changes from 7 commits
a260688
183a928
492f7e4
bb9cc44
df53b68
a256812
176fea9
551c82c
874deb6
607ed2e
4731916
941219c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,17 +64,16 @@ def validate_transactions(self): | |
|
||
# poison pill | ||
if tx == 'stop': | ||
self.q_tx_delete.put('stop') | ||
self.q_tx_validated.put('stop') | ||
return | ||
|
||
self.q_tx_delete.put(tx['id']) | ||
|
||
with self.monitor.timer('validate_transaction', rate=bigchaindb.config['statsd']['rate']): | ||
is_valid_transaction = b.is_valid_transaction(tx) | ||
|
||
if is_valid_transaction: | ||
self.q_tx_validated.put(tx) | ||
else: | ||
self.q_tx_delete.put(tx['id']) | ||
|
||
def create_blocks(self): | ||
""" | ||
|
@@ -126,11 +125,15 @@ def write_blocks(self): | |
|
||
# poison pill | ||
if block == 'stop': | ||
self.q_tx_delete.put('stop') | ||
return | ||
|
||
with self.monitor.timer('write_block'): | ||
b.write_block(block) | ||
|
||
for tx in block['block']['transactions']: | ||
self.q_tx_delete.put(tx['id']) | ||
|
||
def delete_transactions(self): | ||
""" | ||
Delete transactions from the backlog | ||
|
@@ -229,3 +232,89 @@ def _start(self): | |
p_write.start() | ||
p_delete.start() | ||
|
||
|
||
class BacklogDeleteRevert(Block): | ||
|
||
def __init__(self, q_backlog_delete): | ||
# invalid transactions can stay deleted | ||
self.q_tx_to_validate = q_backlog_delete | ||
self.q_tx_validated = mp.Queue() | ||
self.q_transaction_to_revert = mp.Queue() | ||
self.q_tx_delete = mp.Queue() | ||
|
||
self.monitor = Monitor() | ||
|
||
def locate_transactions(self): | ||
""" | ||
Determine if a deleted transaction has made it into a block | ||
""" | ||
# create bigchain instance | ||
b = Bigchain() | ||
|
||
while True: | ||
tx = self.q_tx_validated.get() | ||
|
||
# poison pill | ||
if tx == 'stop': | ||
self.q_tx_delete.put('stop') | ||
self.q_transaction_to_revert.put('stop') | ||
return | ||
|
||
# check if tx is in a (valid) block | ||
validity = b.get_blocks_status_containing_tx(tx['id']) | ||
|
||
if validity and list(validity.values()).count(Bigchain.BLOCK_VALID) == 1: | ||
# tx made it into a block, and can safely be deleted | ||
self.q_tx_delete.put(tx['id']) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need to store the transactions here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As opposed to just the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was more what do we do with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's there because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should not be a problem. You never start the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yikes, my mistake...but couldn't the queue fill up and start throwing exceptions? |
||
else: | ||
# valid tx not in any block, should be re-inserted into backlog | ||
self.q_transaction_to_revert.put(tx) | ||
|
||
def revert_deletes(self): | ||
""" | ||
Put an incorrectly deleted transaction back in the backlog | ||
""" | ||
# create bigchain instance | ||
b = Bigchain() | ||
|
||
while True: | ||
tx = self.q_transaction_to_revert.get() | ||
|
||
# poison pill | ||
if tx == 'stop': | ||
return | ||
|
||
b.write_transaction(tx) | ||
|
||
def empty_delete_q(self): | ||
""" | ||
Empty the delete queue | ||
""" | ||
|
||
while True: | ||
txid = self.q_tx_delete.get() | ||
|
||
# poison pill | ||
if txid == 'stop': | ||
return | ||
|
||
def kill(self): | ||
for i in range(mp.cpu_count()): | ||
self.q_tx_to_validate.put('stop') | ||
|
||
def start(self): | ||
""" | ||
Initialize, spawn, and start the processes | ||
""" | ||
|
||
# initialize the processes | ||
p_validate = ProcessGroup(name='validate_transactions', target=self.validate_transactions) | ||
p_locate = ProcessGroup(name='locate_transactions', target=self.locate_transactions) | ||
p_revert = ProcessGroup(name='revert_deletes', target=self.revert_deletes) | ||
p_empty_delete_q = ProcessGroup(name='empty_delete_q', target=self.empty_delete_q) | ||
|
||
# start the processes | ||
p_validate.start() | ||
p_locate.start() | ||
p_revert.start() | ||
p_empty_delete_q.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.
This will not work like this. There is some period of time since a block is created (and transactions are deleted) and the block is voted valid.
Example timeline:
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 added a tunable delay with the latest commit that should fix the problem. The default is 30s. Can you confirm this fixes the problem? If so I will add the delay to the configurable settings, documentation, etc
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.
Do we need to check the validity of the block? This seems to be doing overlapping work with #193
The way I see it there are 3 different possibilities:
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 only meant to check the validity of transactions -- am I missing something big here?
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 that is true.
I think that it would be better to instead of subclassing
Block
just duplicate thevalidate_transaction
inBacklogDeleteRevert
.This way we don't need to add extra functionality to empty the delete queue and it becomes easier to read the code. Looking at the code it took me some time to figure out how the transactions went from
q_tx_to_validate
toq_tx_validated