-
Notifications
You must be signed in to change notification settings - Fork 130
Limit size of Ibft future message buffer #873
Conversation
@@ -307,7 +309,9 @@ private static ControllerAndState createControllerAndFinalState( | |||
messageValidatorFactory), | |||
messageValidatorFactory), | |||
gossiper, | |||
DUPLICATE_MESSAGE_LIMIT); | |||
DUPLICATE_MESSAGE_LIMIT, |
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.
would probably prefer to see the futureMessageBuffer get created here and passed in (rather than the raw values) - why? Can't answer that.
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.
👍 ^^^
It's cleaner, in terms of IoC and reduces number of constructors on the controller.
I'd suggest instead of passing in values, construct & pass in the objects:
final MessageTracker duplicateMessageTracker, final FutureMessageBuffer futureMessageBuffer
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.
That is cleaner and also reduces the need the seperate constructor in the IbftController.
Done.
return; | ||
} | ||
|
||
if (totalMessages >= futureMessagesLimit) { |
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 had assumed evictMessages() MAY need to loop (i.e. what if you need to remove more than 1 height?) - should this conditional become a loop in evict?
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 don't think there is any need to remove any more than one height at a time. Each height must contain at least one message so if we remove a height we will have room for the message to be added.
} | ||
|
||
if (!buffer.containsKey(msgChainHeight)) { | ||
buffer.put(msgChainHeight, new ArrayList<>()); |
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.
what if this msgChainHeight is higher than the height removed in evictMessage? Eg. MsgChainHeight is 5, but we just removed chain-height 4 ...
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.
Assuming that msgChainHeight is still within the max distance we would add a message for chain height 5. Which is perhaps is a bit odd. Maybe it would be better not to add in that case, essentially evicting itself as the highest chain height? Need to think about this a bit more.
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.
Yeah, I think I'd rather see it evict itself. MAYBE you could do something like add the new message, then run the eviction process.
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.
done. yeah I think it better for it to be evicted. changed the code to run the evict after after adding, avoids needing to special case this add case.
if (buffer.size() > 1) { | ||
buffer.remove(buffer.lastKey()); | ||
} else { | ||
List<Message> messages = buffer.firstEntry().getValue(); |
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.
Is it possible that buffer size is 0? I guess not.
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 am making an assumption that it isn't 0 at this point but that only holds if futureMessagesLimit isn't 0. Be better if the evict messages handled that case, so i'll update evictMessages to handle that properly.
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.
done. added handling of zero message limit.
} | ||
|
||
@VisibleForTesting | ||
FutureMessageBuffer( |
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.
Is this constructor really of use? ...looks like when it's called in the tests a new TreeMap<>
is passed in
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.
It is, I'm using that so I can check the state of the map is correct in the tests without exposing the map to everyone. A new TreeMap<> is passed in, but I'm checking in my tests messages are added to the map correctly.
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.
That's a tight coupling between the test and the specific implementation of the logic, I'm not convinced that's the best approach.
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.
done. updated so don't need special constructor
…d messages or existing buffered messages
} | ||
|
||
private void addMessageToBuffer(final long msgChainHeight, final Message rawMsg) { | ||
if (!buffer.containsKey(msgChainHeight)) { |
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.
nit: could use computeIfAbsent/putIfAbsent
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.
done
this.futureMessagesLimit = futureMessagesLimit; | ||
} | ||
|
||
public void addMessage(final long chainHeight, final long msgChainHeight, final Message rawMsg) { |
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.
don't LOVE msgChainHeight coming in on this API .... rather this get reset in the Poll somehow.
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.
done.changed so it is using been passed in as a arg.
… futureMessageBuffer
private long chainHeight; | ||
|
||
public FutureMessageBuffer( | ||
final long futureMessagesMaxDistance, final long futureMessagesLimit, final int chainHeight) { |
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.
Drop the chainHeight
and initialise it to zero, as the only place it's getting called in code is the IbftController that is passing in a hardcoded zero.
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.
nice catch. that should not of been initialised to zero. fixed now.
this.chainHeight = chainHeight; | ||
} | ||
|
||
public void updateChainHeight(final long chainHeight) { |
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.
sorry to be difficult, are we worried that both this and poll take "chainHeight" - but they are different numbers?
I.e. this is the number of the most recent block on the chain - whereas 'poll' is really the "next" block ...
Wondering if renaming these functions to (something like):
- discardMessagesForHeightsBelow(x)
- extractMessagesWithHeight(y)
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.
The height in the poll is really the message chain height, whereas the updateChainHeight is the current chain height we are working so they are different. I think renaming the arg in poll to msgChainHeight might that clearer.
…t the current chain height
} | ||
|
||
public List<Message> retrieveMessagesForHeight(final long height) { | ||
this.chainHeight = height; |
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.
nit: no need for the 'this'
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.
done
PR description
This add a limit to the number of ibft messages that are stored in the future buffer.
There is a total number of messages that are allowed. And also a max distance from the current height that messages are allowed for.
If the total message limit is reached then all the messages in the highest chain height are removed.
Additionally if there is only one height then we will remove the oldest message to make room instead.
Fixed Issue(s)