Commit fdbbdb8f authored by Mike Curtiss's avatar Mike Curtiss Committed by Jordan DeLong

Add sizeGuess() member to ProducerConsumerQueue

Summary:
This is part 1 of a change to add hysteretic behavior to a blocking queue based on ProducerConsumerQueue.

Knowing the size is useful for monitoring and possibly for objects that contain a ProducerConsumerQueue.

Test Plan:
Added tiny test-case.

Tests pass

Reviewed By: delong.j@fb.com

FB internal diff: D496787
parent 62072424
...@@ -149,6 +149,20 @@ struct ProducerConsumerQueue : private boost::noncopyable { ...@@ -149,6 +149,20 @@ struct ProducerConsumerQueue : private boost::noncopyable {
return true; return true;
} }
// * If called by consumer, then true size may be more (because producer may
// be adding items concurrently).
// * If called by producer, then true size may be less (because consumer may
// be removing items concurrently).
// * It is undefined to call this from any other thread.
size_t sizeGuess() const {
int ret = writeIndex_.load(std::memory_order_consume) -
readIndex_.load(std::memory_order_consume);
if (ret < 0) {
ret += size_;
}
return ret;
}
private: private:
const uint32_t size_; const uint32_t size_;
T* const records_; T* const records_;
......
...@@ -18,12 +18,17 @@ operations: ...@@ -18,12 +18,17 @@ operations:
empty). empty).
* `isEmpty`: Check if the queue is empty. * `isEmpty`: Check if the queue is empty.
* `isFull`: Check if the queue is full. * `isFull`: Check if the queue is full.
* `sizeGuess`: Returns the number of entries in the queue. Because of the
way we coordinate threads, this guess could be slightly wrong
when called by the producer/consumer thread, and it could be
wildly inaccurate if called from any other threads. Hence,
only call from producer/consumer threads!
All of these operations are wait-free. The read operations (including All of these operations are wait-free. The read operations (including
`frontPtr` and `popFront`) and write operations must only be called by the `frontPtr` and `popFront`) and write operations must only be called by the
reader and writer thread, respectively. `isFull` and `isEmpty` may be called by reader and writer thread, respectively. `isFull`, `isEmpty`, and `sizeGuess`
either thread, but the return values from `read`, `write`, or `frontPtr` are may be called by either thread, but the return values from `read`, `write`, or
sufficient for most cases. `frontPtr` are sufficient for most cases.
`write` may fail if the queue is full, and `read` may fail if the queue is `write` may fail if the queue is full, and `read` may fail if the queue is
empty, so in many situations it is important to choose the queue size such that empty, so in many situations it is important to choose the queue size such that
......
...@@ -281,4 +281,5 @@ TEST(PCQ, EmptyFull) { ...@@ -281,4 +281,5 @@ TEST(PCQ, EmptyFull) {
EXPECT_TRUE(queue.isFull()); // Tricky: full after 2 writes, not 3. EXPECT_TRUE(queue.isFull()); // Tricky: full after 2 writes, not 3.
EXPECT_FALSE(queue.write(3)); EXPECT_FALSE(queue.write(3));
EXPECT_EQ(queue.sizeGuess(), 2);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment