Add LockedRingBuffer

This is a refactor for DnsQueryLog. No functional behavior change.

Bug: 79727473
Test: resolv_unit_test passed
Test: adb shell dumpsys dnsresolver querylog
Change-Id: Id9fc9b7868dab5861feda5ab2cb04759e7a34846
diff --git a/DnsQueryLog.cpp b/DnsQueryLog.cpp
index 6f0e179..b9f6f80 100644
--- a/DnsQueryLog.cpp
+++ b/DnsQueryLog.cpp
@@ -59,11 +59,7 @@
 }  // namespace
 
 void DnsQueryLog::push(Record&& record) {
-    std::lock_guard guard(mLock);
-    mQueue.push_back(std::move(record));
-    if (mQueue.size() > mCapacity) {
-        mQueue.pop_front();
-    }
+    mQueue.push(std::move(record));
 }
 
 void DnsQueryLog::dump(netdutils::DumpWriter& dw) const {
@@ -71,8 +67,7 @@
     netdutils::ScopedIndent indentStats(dw);
     const auto now = std::chrono::system_clock::now();
 
-    std::lock_guard guard(mLock);
-    for (const auto& record : mQueue) {
+    for (const auto& record : mQueue.copy()) {
         if (now - record.timestamp > mValidityTimeMs) continue;
 
         const std::string maskedHostname = maskHostname(record.hostname);
diff --git a/DnsQueryLog.h b/DnsQueryLog.h
index c19f8db..3e6478e 100644
--- a/DnsQueryLog.h
+++ b/DnsQueryLog.h
@@ -17,16 +17,16 @@
 
 #pragma once
 
-#include <deque>
 #include <string>
 #include <vector>
 
-#include <android-base/thread_annotations.h>
 #include <netdutils/DumpWriter.h>
 
+#include "LockedQueue.h"
+
 namespace android::net {
 
-// A circular buffer based class used for query logging. It's thread-safe for concurrent access.
+// This class stores query records in a locked ring buffer. It's thread-safe for concurrent access.
 class DnsQueryLog {
   public:
     static constexpr std::string_view DUMP_KEYWORD = "querylog";
@@ -52,15 +52,13 @@
     // Allow the tests to set the capacity and the validaty time in milliseconds.
     DnsQueryLog(size_t size = kDefaultLogSize,
                 std::chrono::milliseconds time = kDefaultValidityMinutes)
-        : mCapacity(size), mValidityTimeMs(time) {}
+        : mQueue(size), mValidityTimeMs(time) {}
 
-    void push(Record&& record) EXCLUDES(mLock);
-    void dump(netdutils::DumpWriter& dw) const EXCLUDES(mLock);
+    void push(Record&& record);
+    void dump(netdutils::DumpWriter& dw) const;
 
   private:
-    mutable std::mutex mLock;
-    std::deque<Record> mQueue GUARDED_BY(mLock);
-    const size_t mCapacity;
+    LockedRingBuffer<Record> mQueue;
     const std::chrono::milliseconds mValidityTimeMs;
 
     // The capacity of the circular buffer.
diff --git a/LockedQueue.h b/LockedQueue.h
index 0481eda..8694f2d 100644
--- a/LockedQueue.h
+++ b/LockedQueue.h
@@ -46,6 +46,30 @@
     std::deque<T> mQueue GUARDED_BY(mLock);
 };
 
+template <typename T>
+class LockedRingBuffer {
+  public:
+    explicit LockedRingBuffer(size_t size) : mCapacity(size) {}
+
+    void push(T&& record) {
+        std::lock_guard guard(mLock);
+        mQueue.push_back(std::move(record));
+        if (mQueue.size() > mCapacity) {
+            mQueue.pop_front();
+        }
+    }
+
+    std::deque<T> copy() const {
+        std::lock_guard guard(mLock);
+        return mQueue;
+    }
+
+  private:
+    mutable std::mutex mLock;
+    const size_t mCapacity;
+    std::deque<T> mQueue GUARDED_BY(mLock);
+};
+
 }  // end of namespace net
 }  // end of namespace android