Parcourir la source

[1067] Interface definitions for iterating database

* DatabaseClient::getIterator
* DatabaseConnection::getIteratorContext
* DatabaseConnection::IteratorContext

Nothing is implemented, it's just the header parts and doxygen comments.
Michal 'vorner' Vaner il y a 13 ans
Parent
commit
07cd164792
2 fichiers modifiés avec 104 ajouts et 0 suppressions
  1. 97 0
      src/lib/datasrc/database.h
  2. 7 0
      src/lib/datasrc/tests/database_unittest.cc

+ 97 - 0
src/lib/datasrc/database.h

@@ -17,6 +17,8 @@
 
 #include <datasrc/client.h>
 
+#include <exceptions/exceptions.h>
+
 namespace isc {
 namespace datasrc {
 
@@ -71,6 +73,84 @@ public:
      *     an opaque handle.
      */
     virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const = 0;
+    /**
+     * \brief This holds the internal context of ZoneIterator for databases
+     *
+     * While the ZoneIterator implementation from DatabaseClient does all the
+     * translation from strings to DNS classes and validation, this class
+     * holds the pointer to where the database is at reading the data.
+     *
+     * It can either hold shared pointer to the connection which created it
+     * and have some kind of statement inside (in case single database
+     * connection can handle multiple concurrent SQL statements) or it can
+     * create a new connection (or, if it is more convenient, the connection
+     * itself can inherit both from DatabaseConnection and IteratorContext
+     * and just clone itself).
+     */
+    class IteratorContext : public boost::noncopyable {
+    public:
+        /**
+         * \brief Destructor
+         *
+         * Virtual destructor, so any descendand class is destroyed correctly.
+         */
+        virtual ~IteratorContext() { }
+        /**
+         * \brief Function to provide next resource record
+         *
+         * This function should provide data about the next resource record
+         * from the iterated zone. The data are not converted yet.
+         *
+         * The order of RRs is not strictly set, but the RRs for single RRset
+         * must not be interlieved with any other RRs (eg. RRsets must be
+         * "together").
+         *
+         * \param name The name of the RR will be returned here.
+         * \param rtype The string representation of RRType will be returned
+         *     through this parameter.
+         * \param ttl The time to live output parameter.
+         * \param data This is where the string representation of data will be
+         *     put.
+         * \return If there was RR returned. Once it returns false, the zone
+         *     was iterated to its end.
+         * \todo Do we consider databases where it is stored in binary blob
+         *     format?
+         */
+        virtual bool getNext(std::string& name, std::string& rtype, int& ttl,
+                             std::string& data) = 0;
+    };
+    typedef boost::shared_ptr<IteratorContext> IteratorContextPtr;
+    /**
+     * \brief Creates an iterator context for given zone.
+     *
+     * This should create a new iterator context to be used by
+     * DatabaseConnection's ZoneIterator. It can be created based on the name
+     * or the ID (returned from getZone()), what is more comfortable for the
+     * database implementation. Both are provided (and are guaranteed to match,
+     * the DatabaseClient first looks up the zone ID and then calls this).
+     *
+     * The default implementation throws isc::NotImplemented, to allow
+     * "minimal" implementations of the connection not supporting optional
+     * functionality.
+     *
+     * \param name The name of the zone.
+     * \param id The ID of the zone, returned from getZone().
+     * \return Newly created iterator context. Must not be NULL.
+     */
+    virtual IteratorContextPtr getIteratorContext(const isc::dns::Name& name,
+                                                  int id) const
+    {
+        /*
+         * This is a compromise. We need to document the parameters in doxygen,
+         * so they need a name, but then it complains about unused parameter.
+         * This is a NOP that "uses" the parameters.
+         */
+        static_cast<void>(name);
+        static_cast<void>(id);
+
+        isc_throw(isc::NotImplemented,
+                  "This database datasource can't be iterated");
+    }
 };
 
 /**
@@ -181,6 +261,23 @@ public:
      *     returned, though.
      */
     virtual FindResult findZone(const isc::dns::Name& name) const;
+    /**
+     * \brief Get the zone iterator
+     *
+     * The iterator allows going through the whole zone content. If the
+     * underlying DatabaseConnection is implemented correctly, it should
+     * be possible to have multiple ZoneIterators at once and query data
+     * at the same time.
+     *
+     * \exception DataSourceError if the zone doesn't exist.
+     * \exception isc::NotImplemented if the underlying DatabaseConnection
+     *     doesn't implement iteration.
+     * \exception Anything else the underlying DatabaseConnection might
+     *     want to throw.
+     * \param name The origin of the zone to iterate.
+     * \return Shared pointer to the iterator (it will never be NULL)
+     */
+    virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name) const;
 private:
     /// \brief Our connection.
     const std::auto_ptr<DatabaseConnection> connection_;

+ 7 - 0
src/lib/datasrc/tests/database_unittest.cc

@@ -41,6 +41,13 @@ public:
     }
 };
 
+// This tests the default getIteratorContext behaviour, throwing NotImplemented
+TEST(DatabaseConnectionTest, getIteratorContext) {
+    // The parameters don't matter
+    EXPECT_THROW(MockConnection().getIteratorContext(Name("."), 1),
+                 isc::NotImplemented);
+}
+
 class DatabaseClientTest : public ::testing::Test {
 public:
     DatabaseClientTest() {