-
Notifications
You must be signed in to change notification settings - Fork 18
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
Use double-buffering to fetch the records from the one during iteration #60
Use double-buffering to fetch the records from the one during iteration #60
Conversation
51a923d
to
6dc1f9f
Compare
private void[]*[2] batch_buffers; | ||
|
||
/// Index of the batch we're currently iterating over | ||
private int current_buffer; |
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 would use bool
...
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 would still prefer int
though, because it doesn't restrict the number of the buffers artificially to two (it's easy to generalize this to N buffers this way). For the same reason I would stick with modulo arithmetic.
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.
As an alternative you could use void[]* front_buffer, back_buffer
and swap them in the swap
method. This would avoid the need for current_buffer
and the buffer getter methods.
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.
OK, that's more neat. I'll take that suggestion 👍
/// Swaps the front and back buffer | ||
private void swap () | ||
{ | ||
this.current_buffer = (this.current_buffer + 1) % 2; |
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.current_buffer = !this.current_buffer
?
private int current_buffer; | ||
|
||
/// Initializes the double buffer | ||
void init (void[]* delegate() getVoidBuffer) |
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.
lazy void[]*
if you want to be cool ;)
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.
Hmm, I think the way it is consistent with rest of the swarm - we're passing acquires as delegates.
6dc1f9f
to
e447603
Compare
Adapted to @david-eckardt-sociomantic 's proposal with fields. |
{ | ||
auto tmp = this.front_buffer; | ||
this.front_buffer = this.back_buffer; | ||
this.back_buffer = tmp; |
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.
typeid(void[]*).swap(&this.front_buffer, &this.back_buffer)
(just kidding)
private void[]* back_buffer; | ||
|
||
/// Initializes the double buffer | ||
void init (void[]* delegate() getVoidBuffer) |
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.
private
?
e447603
to
754910f
Compare
Updated with |
754910f
to
618cdbb
Compare
/// Acquired buffers to store batches of records. Reader always | ||
/// appends to the back one and the RecordStream always uses the | ||
/// front one. | ||
private void[]* front_buffer; |
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.
You could even name them reader_buffer
and record_stream_buffer
, to make it super clear which is which.
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.
Right, or just output
and input
. (The _buffer
suffix isn't needed.)
// Grab the back buffer and move it to the front | ||
this.buffers.swap(); | ||
|
||
return !this.stopped || this.buffers.front_buffer.length; |
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.
Tiny adjustment: (*this.buffers.front_buffer).length
, for consistency.
A higher level idea: would it be possible to completely encapsulate the buffer handling, so that the reader and record stream fibers don't need to know anything about it? They would just push and pop records to/from the buffer. |
Note that the |
618cdbb
to
266b211
Compare
Updated with encapsulation of I think right now the complexity is quite low, I wouldn't try going further than this, but I'm open to comments. |
Fair enough. I think it probably could be done in a nice way, but it's not incredibly important, right now. |
/// ditto | ||
private void[]* input; | ||
|
||
/// Initializes the double buffer |
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.
Hey! I just noticed you're trying to sneak in a new method doc format! Cheeky ;)
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.
How would you ever set the precedent without sneaking it in? :-)
/// front one. | ||
private void[]* output; | ||
|
||
/// ditto |
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'd be clearer for each buffer to have its own comment.
|
||
**********************************************************************/ | ||
|
||
private bool waitForRecords () | ||
{ | ||
this.suspendFiber(FiberSuspended.WaitingForRecords); | ||
return !this.stopped; | ||
// In case we already have the batch, don't wait for it |
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 make more sense reversed: "Wait for the next batch, unless we already have one.".
|
||
if (!(*this.batch_buffer).length) | ||
enableStomping(*this.batch_buffer); | ||
if (!(*batch_buffer).length) |
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 seem sensible (and simple) to encapsulate this in some kind of push
method.
The previous approach where the client would ask for the batch from the node was prone to the latency problems - if the time to prepare and send batch is non-negligible the performance of the client application would suffer. This patch improves the situation and decreases the latency in the following way: - As soon as client get the new batch from the node, it will request another one - When the new batch arrives the client will store it in the back buffer, ready for processing as soon as it finish with the previous one - After processing the previous batch and the new batch already arrived, the client will just swap the buffers, reading from the new one.
266b211
to
bc0fb50
Compare
Updated with the addressed comments by @gavin-norman-sociomantic . |
The previous approach where the client would ask for the batch from the
node was prone to the latency problems - if the time to prepare and send
batch is non-negligible the performance of the client application would
suffer. This patch improves the situation and decreases the latency in
the following way:
buffer, ready for processing as soon as it finish with the previous one
the client will just swap the buffers, reading from the new one.