Add sizeGuess() member to ProducerConsumerQueue
authorMike Curtiss <mcurtiss@fb.com>
Thu, 7 Jun 2012 07:32:14 +0000 (00:32 -0700)
committerJordan DeLong <jdelong@fb.com>
Fri, 22 Jun 2012 02:38:51 +0000 (19:38 -0700)
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

folly/ProducerConsumerQueue.h
folly/docs/ProducerConsumerQueue.md
folly/test/ProducerConsumerQueueTest.cpp

index d5d41aaf8dbeae57e7958ddebe49af3581edf484..670f725436da5be8bcf64b179df7204966e4a3f0 100644 (file)
@@ -149,6 +149,20 @@ struct ProducerConsumerQueue : private boost::noncopyable {
     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:
   const uint32_t size_;
   T* const records_;
index 40ae8cab8996527bb8fe26ef56a8ec551e2c1b79..22d50f2ca79a6f0b71a9da62e47759fbbbbbe669 100644 (file)
@@ -18,12 +18,17 @@ operations:
                empty).
  * `isEmpty`: Check if the queue is empty.
  * `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
 `frontPtr` and `popFront`) and write operations must only be called by the
-reader and writer thread, respectively. `isFull` and `isEmpty` may be called by
-either thread, but the return values from `read`, `write`, or `frontPtr` are
-sufficient for most cases.
+reader and writer thread, respectively. `isFull`, `isEmpty`, and `sizeGuess`
+may be called by either thread, but the return values from `read`, `write`, or
+`frontPtr` are sufficient for most cases.
 
 `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
index 06030481ce04d19825b062565bb0582f68674a76..feaf8a630f86b4710ebf8412ed175edbda706808 100644 (file)
@@ -281,4 +281,5 @@ TEST(PCQ, EmptyFull) {
   EXPECT_TRUE(queue.isFull());  // Tricky: full after 2 writes, not 3.
 
   EXPECT_FALSE(queue.write(3));
+  EXPECT_EQ(queue.sizeGuess(), 2);
 }