From 7e55292dffb7e8c76b709980940f8edd7e202a11 Mon Sep 17 00:00:00 2001
From: Anushree Jha <anushreejha0604@gmail.com>
Date: Fri, 10 Jan 2025 22:21:57 +0530
Subject: [PATCH] Add GetAllSnapshots functionality to SnapshotList (#1240)

---
 CMakeLists.txt       |  1 +
 db/db_impl.cc        |  8 ++++++++
 db/db_impl.h         |  4 ++++
 db/snapshot.h        | 11 +++++++++++
 db/snapshot_test.cc  | 30 ++++++++++++++++++++++++++++++
 include/leveldb/db.h |  3 +++
 6 files changed, 57 insertions(+)
 create mode 100644 db/snapshot_test.cc

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fda9e01..060c3d6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,6 +330,7 @@ if(LEVELDB_BUILD_TESTS)
         "db/autocompact_test.cc"
         "db/corruption_test.cc"
         "db/db_test.cc"
+        "db/snapshot_test.cc"
         "db/dbformat_test.cc"
         "db/filename_test.cc"
         "db/log_test.cc"
diff --git a/db/db_impl.cc b/db/db_impl.cc
index f96d245..8ca2b73 100644
--- a/db/db_impl.cc
+++ b/db/db_impl.cc
@@ -1575,4 +1575,12 @@ Status DestroyDB(const std::string& dbname, const Options& options) {
   return result;
 }
 
+std::vector<const Snapshot*> DBImpl::GetAllSnapshots() {
+  std::vector<const Snapshot*> snapshots;
+  mutex_.Lock();
+  snapshots = snapshots_.GetAllSnapshots();  // Call the SnapshotList method
+  mutex_.Unlock();
+  return snapshots;
+}
+
 }  // namespace leveldb
diff --git a/db/db_impl.h b/db/db_impl.h
index c7b0172..d98ab1e 100644
--- a/db/db_impl.h
+++ b/db/db_impl.h
@@ -9,6 +9,7 @@
 #include <deque>
 #include <set>
 #include <string>
+#include <vector> 
 
 #include "db/dbformat.h"
 #include "db/log_writer.h"
@@ -48,6 +49,9 @@ class DBImpl : public DB {
   bool GetProperty(const Slice& property, std::string* value) override;
   void GetApproximateSizes(const Range* range, int n, uint64_t* sizes) override;
   void CompactRange(const Slice* begin, const Slice* end) override;
+ 
+  // Retrieve all active snapshots in the database
+  std::vector<const Snapshot*> GetAllSnapshots() override;
 
   // Extra methods (for testing) that are not in the public DB interface
 
diff --git a/db/snapshot.h b/db/snapshot.h
index 817bb7b..5be56ac 100644
--- a/db/snapshot.h
+++ b/db/snapshot.h
@@ -85,6 +85,17 @@ class SnapshotList {
     delete snapshot;
   }
 
+  // Retrieves all snapshots in the list.
+  //
+  // This method iterates through the linked list and collects all snapshots.
+  std::vector<const Snapshot*> GetAllSnapshots() const {
+    std::vector<const Snapshot*> snapshots;
+    for (const SnapshotImpl* s = head_.next_; s != &head_; s = s->next_) {
+      snapshots.push_back(static_cast<const Snapshot*>(s));
+    }
+    return snapshots;
+  }
+
  private:
   // Dummy head of doubly-linked list of snapshots
   SnapshotImpl head_;
diff --git a/db/snapshot_test.cc b/db/snapshot_test.cc
new file mode 100644
index 0000000..ea1b03f
--- /dev/null
+++ b/db/snapshot_test.cc
@@ -0,0 +1,30 @@
+#include "db/db_impl.h"
+#include "gtest/gtest.h"
+
+namespace leveldb {
+
+// Test to validate GetAllSnapshots retrieves all snapshots correctly.
+TEST(SnapshotTest, GetAllSnapshots) {
+  SnapshotList snapshot_list;
+
+  // Create some snapshots
+  SnapshotImpl* s1 = snapshot_list.New(1);
+  SnapshotImpl* s2 = snapshot_list.New(2);
+  SnapshotImpl* s3 = snapshot_list.New(3);
+
+  // Use GetAllSnapshots to retrieve them
+  std::vector<const Snapshot*> snapshots = snapshot_list.GetAllSnapshots();
+
+  // Validate the results
+  ASSERT_EQ(snapshots.size(), 3);
+  EXPECT_EQ(static_cast<const SnapshotImpl*>(snapshots[0])->sequence_number(), 1);
+  EXPECT_EQ(static_cast<const SnapshotImpl*>(snapshots[1])->sequence_number(), 2);
+  EXPECT_EQ(static_cast<const SnapshotImpl*>(snapshots[2])->sequence_number(), 3);
+
+  // Clean up
+  snapshot_list.Delete(s1);
+  snapshot_list.Delete(s2);
+  snapshot_list.Delete(s3);
+}
+
+}  
diff --git a/include/leveldb/db.h b/include/leveldb/db.h
index a13d147..a79aa9c 100644
--- a/include/leveldb/db.h
+++ b/include/leveldb/db.h
@@ -145,6 +145,9 @@ class LEVELDB_EXPORT DB {
   // Therefore the following call will compact the entire database:
   //    db->CompactRange(nullptr, nullptr);
   virtual void CompactRange(const Slice* begin, const Slice* end) = 0;
+
+  // Retrieve all active snapshots in the database.
+  virtual std::vector<const Snapshot*> GetAllSnapshots() = 0;
 };
 
 // Destroy the contents of the specified database.