Http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-writing-to-ring.html author is Trisha Gee, a female engineer at Lmax.
This is a chapter missing from the end-to-end view. Be careful. This article is very long. But in order for you to connect to the context for reading, I decided to write them into a blog.
TheKey PointsYes: do not overlap the ring; notify consumers; batch processing at the producer end; and how multiple producers work together.
Producerbarriers
Disruptor codeConsumerProvides some interfaces and auxiliary classes, but does not write the ring BufferProducerProvides interfaces. This is because no one except you need to know the producer needs to access it. Even so, the ring buffer provides a producerbarrier object like the consumer, allowing the producer to write the ring buffer through it.
Writing a ring buffer involves two-phase commit (two-phase commit ). First, your producer needs to apply for the next node in the buffer. Then, when the producer ends writing data to the node, it needs to call the commit method of producerbarrier.
Let's take a look at the first step. It sounds easy-"Give me the next node in the ring buffer ". Well, from the producer's point of view, it is very simple: simply call the nextentry () method of producerbarrier, which will return you an entry object, which is the next node of the ring buffer.
How does producerbarrier prevent ring buffer overlap?
In the background, producerbarrier is responsible for all interaction details to find the next node from the ring buffer before the producer can write data to it.
(I'm not sure whether the shiny new tablet can help improve the image definition, but it is very interesting to use ).
In this figure, we assume that only one producer writes the ring buffer. After a while, we will deal with the complex problems of multiple producers.
ConsumertrackingproducerbarrierThe object has allConsumerList. This looks a bit strange-I never expected producerbarrier to know anything about the consumer side. But wait, there is a reason. Because we don't want to be confused with the queue (the queue needs to track the header and tail of the queue, and sometimes they point to the same location), the disruptor is responsible for notifying the consumer of the serial number they processed, rather than ring buffer. Therefore, if we want to determine that we have not overlapped the ring buffer, we need to check where all consumers have read it.
In, there isConsumerThe maximum number 12 was successfully read (highlighted in red/pink ). SecondConsumerA little backward -- maybe it is doing I/O operations and so on -- it stops at number 3. Therefore, before catching up with consumer 1, consumer 2 must finish the whole ring buffer circle.
Now the producer wants to write the node occupied by serial number 3 in the ring buffer because it is the next node of the current cursor of the ring buffer. However, producerbarrier understands that data cannot be written because a consumer is occupying it. Therefore, producerbarrier stops to spin (spins) and waits until the consumer leaves.
Apply for the next node
Now we can imagine that consumer 2 has processed a batch of nodes and moved its serial number forward. It may be moved to number 9 (because of the batch processing method on the consumer end, in reality I will expect it to reach 12, but that is not an interesting example ).
Displays the situation when consumer 2 moves to number 9. In this figure, I have ignored consumerbarrier because it is not involved in this scenario.
Producerbarier will see that the next node -- number 3 is ready for use. It will seize the entry on this node (I have not introduced the entry object, basically it is a bucket for storing the ring buffer data written to a sequence number ), update the next sequence number (13) to the entry sequence number, and return the entry to the producer. The producer can then write data to the entry.
Submit new data
The second step of the two-phase commit is-yes, commit.
Green indicates the recently written entry. The serial number is 13 -- er. Sorry, I am also red-green blind. But other colors are even worse.
When the producer ends writing data to the entry, it will require the producerbarrier to submit.
Producerbarrier waits for the cursor of the ring buffer to catch up with the current position (this is meaningless for a single producer-for example, we already know that the cursor has reached 12, and no one else is writing the ring buffer ). Then producerbarrier updates the cursor of the ring buffer to the entry number written just now-here we are 13. Next, producerbarrier will let consumers know that there are new things in the buffer. It stamps the waitstrategy object on the consumerbarrier and says, "Hey, wake up! Something happened !" (Note-different waitstrategy implementations implement reminders in different ways, depending on whether it uses the blocking mode .)
Now consumer 1 can read the data of entry 13, consumer 2 can read entry 13 and all the data above, and then they are all very happy.
Batch Processing on producerbarrier
Interestingly, disruptor can implement batch processing at both the producer and consumer ends. Remember thatProgramRun. Has consumer 2 reached the number 9 at last? Producerbarrier can do something tricky here-It knows the size of the ring buffer and the slowest consumer location. Therefore, it can discover which nodes are currently available.
If producerbarrier knows that the cursor of the ring buffer points to 12, and the slowest consumer is at 9, it allows the producer to write nodes 3, 4, 5, 6, 7, and 8, you do not need to check the consumer location again in the middle.
Scenarios with multiple producers
Here you may think that I have finished speaking, but there are still some details.
In the above figure, I lied a little bit. I hinted that the sequence number obtained by producerbarrier is directly from the cursor of the ring buffer. However, if you have readCodeYou will find that it is obtained through claimstrategy. I omit this object to simplify it. It is not very important for a single producer.
In scenarios with multiple producers, you also need other items to track the serial number. This sequence number refers to the number currently writable. Note that this is different from "adding 1 to the ring buffer cursor"-if more than one producer writes data to the ring buffer at the same time, some entries may be written by the producer but not submitted yet.
Let's review how to apply for writing nodes. Each producer applies to claimstrategy for the next available node. Producer 1 obtains serial number 13, which is the same as that of a single producer above. Producer 2 obtains the serial number 14, although the current cursor of the ring buffer only points to 12. This is because claimsequence is not only responsible for distributing serial numbers, but also for tracking which serial numbers have been allocated.
Each producer now has its own write node and a brand new serial number.
I green producer 1 and its write nodes, and painted suspicious pink-It looks purple.
Now let's assume that producer 1 still lives in the fairy tale, and for some reason it is not possible to submit data. Producer 2 is ready to submit and sends a request to producerbarrier.
As we have seen in the previous commit, producerbarrier will only be submitted when the ring buffer cursor reaches the previous node of the node to be submitted. In the current situation, the cursor must first reach the number 13 to submit the data of node 14. However, we cannot do this because producer 1 is staring at some of the glittering things and has no time to submit them. Therefore, claimstrategy stops at spins until the Bing buffer cursor reaches the position where it should be.
Now producer 1 wakes up from the confusion and applies to submit data for node 13 (the Green Arrow from producer 1 indicates this request ). Producerbarrier asked claimstrategy to wait for the cursor of the ring buffer to reach serial number 12. Of course, it is now. Therefore, the ring buffer moves the cursor to 13. Let producerbarrier stamp waitstrategy and tell everyone that the ring buffer has been updated. Now producerbarrier can complete the request of producer 2, move the Bing buffer cursor to 14, and notify everyone.
Although the producer completes Data Writing at different times, the content sequence of the ring buffer always follows the initial call sequence of nextentry. That is to say, if a producer is suspended when writing data to bing buffer, It will be executed immediately only when it is released.
Call --. I finally managed to finish everything and didn't mention the memory barrier at once ).
UPDATE: The latest ringbuffer version removes the producer barrier. If the producerbarrier cannot be found in the code you see, let's assume that when I say "producer barrier", I mean "Ring buffer ".
Update 2: note that disruptor 2.0 is named differently from this document. If you are confused about the class name, please read my change summary.