Parcourir la source

[1329] a snapshot push: including diffs table schema and initial code for
adding diffs.

JINMEI Tatuya il y a 13 ans
Parent
commit
0ea04c4bb2

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

@@ -113,6 +113,20 @@ public:
         DEL_PARAM_COUNT = 3 ///< Number of parameters
         DEL_PARAM_COUNT = 3 ///< Number of parameters
     };
     };
 
 
+    /// TBD
+    enum DiffOperation {
+        DIFF_ADD = 0,
+        DIFF_DELETE = 1
+    };
+
+    enum DiffRecordParams {
+        DIFF_NAME = 0,
+        DIFF_TYPE = 1,
+        DIFF_TTL = 2,
+        DIFF_RDATA = 3,
+        DIFF_PARAM_COUNT = 4
+    };
+
     /**
     /**
      * \brief Destructor
      * \brief Destructor
      *
      *
@@ -453,6 +467,14 @@ public:
     /// to the method or internal database error.
     /// to the method or internal database error.
     virtual void rollback() = 0;
     virtual void rollback() = 0;
 
 
+    /// TBD
+    /// Must be in a transaction.  (should that be started by startUpdateZone,
+    /// or can that be any transaction? => probably yes in future, so include
+    /// zone_id in param, but for now assume using it with startUpdateZone)
+    virtual void addRecordDiff(
+        int zone_id, uint32_t serial, DiffOperation operation,
+        const std::string (&params)[DIFF_PARAM_COUNT]) = 0;
+
     /// Clone the accessor with the same configuration.
     /// Clone the accessor with the same configuration.
     ///
     ///
     /// Each derived class implementation of this method will create a new
     /// Each derived class implementation of this method will create a new

+ 71 - 3
src/lib/datasrc/sqlite3_accessor.cc

@@ -52,7 +52,9 @@ enum StatementID {
     DEL_RECORD = 8,
     DEL_RECORD = 8,
     ITERATE = 9,
     ITERATE = 9,
     FIND_PREVIOUS = 10,
     FIND_PREVIOUS = 10,
-    NUM_STATEMENTS = 11
+    ADD_RECORD_DIFF = 11,
+    GET_RECORD_DIFF = 12,       // This is temporary for testing "add diff"
+    NUM_STATEMENTS = 13
 };
 };
 
 
 const char* const text_statements[NUM_STATEMENTS] = {
 const char* const text_statements[NUM_STATEMENTS] = {
@@ -81,7 +83,12 @@ const char* const text_statements[NUM_STATEMENTS] = {
      */
      */
     "SELECT name FROM records " // FIND_PREVIOUS
     "SELECT name FROM records " // FIND_PREVIOUS
     "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
     "WHERE zone_id=?1 AND rdtype = 'NSEC' AND "
-    "rname < $2 ORDER BY rname DESC LIMIT 1"
+    "rname < $2 ORDER BY rname DESC LIMIT 1",
+    "INSERT INTO diffs "        // ADD_RECORD_DIFF
+    "(zone_id, version, operation, name, rrtype, ttl, rdata) "
+    "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)"
+    , "SELECT name, rrtype, ttl, rdata, version, operation " // GET_RECORD_DIFF
+    "FROM diffs WHERE zone_id = ?1 ORDER BY id, operation"
 };
 };
 
 
 struct SQLite3Parameters {
 struct SQLite3Parameters {
@@ -206,6 +213,11 @@ const char* const SCHEMA_LIST[] = {
     "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
     "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
     "rdata STRING NOT NULL)",
     "rdata STRING NOT NULL)",
     "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
     "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+    "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
+    "zone_id INTEGER NOT NULL, version INTEGER NOT NULL, "
+    "operation INTEGER NOT NULL, name STRING NOT NULL COLLATE NOCASE, "
+    "rrtype STRING NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
+    "rdata STRING NOT NULL)",
     NULL
     NULL
 };
 };
 
 
@@ -214,7 +226,7 @@ prepare(sqlite3* const db, const char* const statement) {
     sqlite3_stmt* prepared = NULL;
     sqlite3_stmt* prepared = NULL;
     if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
     if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
         isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
         isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
-                  statement);
+                  statement << ": " << sqlite3_errmsg(db));
     }
     }
     return (prepared);
     return (prepared);
 }
 }
@@ -681,6 +693,62 @@ SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
         *dbparameters_, DEL_RECORD, params, "delete record from zone");
         *dbparameters_, DEL_RECORD, params, "delete record from zone");
 }
 }
 
 
+void
+SQLite3Accessor::addRecordDiff(int zone_id, uint32_t serial,
+                               DiffOperation operation,
+                               const std::string (&params)[DIFF_PARAM_COUNT])
+{
+    // TBD condition check
+
+    sqlite3_stmt* const stmt = dbparameters_->statements_[ADD_RECORD_DIFF];
+    StatementProcessor executer(*dbparameters_, ADD_RECORD_DIFF,
+                                "add record diff");
+    int param_id = 0;
+    if (sqlite3_bind_int(stmt, ++param_id, zone_id)
+        != SQLITE_OK) {
+        isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
+                  sqlite3_errmsg(dbparameters_->db_));
+    }
+    if (sqlite3_bind_int64(stmt, ++param_id, serial)
+        != SQLITE_OK) {
+        isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
+                  sqlite3_errmsg(dbparameters_->db_));
+    }
+    if (sqlite3_bind_int(stmt, ++param_id, operation)
+        != SQLITE_OK) {
+        isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
+                  sqlite3_errmsg(dbparameters_->db_));
+    }
+    for (int i = 0; i < DIFF_PARAM_COUNT; ++i) {
+        if (sqlite3_bind_text(stmt, ++param_id, params[i].c_str(),
+                              -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+            isc_throw(DataSourceError, "failed to bind SQLite3 parameter: " <<
+                      sqlite3_errmsg(dbparameters_->db_));
+        }
+    }
+    executer.exec();
+}
+
+vector<vector<string> >
+SQLite3Accessor::getRecordDiff(int zone_id) {
+    sqlite3_stmt* const stmt = dbparameters_->statements_[GET_RECORD_DIFF];
+    sqlite3_bind_int(stmt, 1, zone_id);
+
+    vector<vector<string> > result;
+    while (sqlite3_step(stmt) == SQLITE_ROW) {
+        vector<string> row_result;
+        for (int i = 0; i < 6; ++i) {
+            row_result.push_back(convertToPlainChar(sqlite3_column_text(stmt,
+                                                                        i),
+                                                    dbparameters_->db_));
+        }
+        result.push_back(row_result);
+    }
+    sqlite3_reset(stmt);
+
+    return (result);
+}
+
 std::string
 std::string
 SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
 SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
     const
     const

+ 8 - 0
src/lib/datasrc/sqlite3_accessor.h

@@ -157,6 +157,14 @@ public:
     virtual void deleteRecordInZone(
     virtual void deleteRecordInZone(
         const std::string (&params)[DEL_PARAM_COUNT]);
         const std::string (&params)[DEL_PARAM_COUNT]);
 
 
+    virtual void addRecordDiff(
+        int zone_id, uint32_t serial, DiffOperation operation,
+        const std::string (&params)[DIFF_PARAM_COUNT]);
+
+    // A short term method for tests until we implement more complete
+    // API to retrieve diffs.
+    std::vector<std::vector<std::string> > getRecordDiff(int zone_id);
+
     /// The SQLite3 implementation of this method returns a string starting
     /// The SQLite3 implementation of this method returns a string starting
     /// with a fixed prefix of "sqlite3_" followed by the DB file name
     /// with a fixed prefix of "sqlite3_" followed by the DB file name
     /// removing any path name.  For example, for the DB file
     /// removing any path name.  For example, for the DB file

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

@@ -233,6 +233,8 @@ public:
     virtual void rollback() {}
     virtual void rollback() {}
     virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
     virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
     virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
     virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
+    virtual void addRecordDiff(int, uint32_t, DiffOperation,
+                               const std::string (&)[DIFF_PARAM_COUNT]) {}
 
 
     virtual const std::string& getDBName() const {
     virtual const std::string& getDBName() const {
         return (database_name_);
         return (database_name_);

+ 64 - 2
src/lib/datasrc/tests/sqlite3_accessor_unittest.cc

@@ -22,6 +22,7 @@
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
+#include <boost/lexical_cast.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <fstream>
 #include <fstream>
 #include <sqlite3.h>
 #include <sqlite3.h>
@@ -29,6 +30,7 @@
 using namespace std;
 using namespace std;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
 using boost::shared_ptr;
 using boost::shared_ptr;
+using boost::lexical_cast;
 using isc::data::ConstElementPtr;
 using isc::data::ConstElementPtr;
 using isc::data::Element;
 using isc::data::Element;
 using isc::dns::RRClass;
 using isc::dns::RRClass;
@@ -214,8 +216,7 @@ TEST(SQLite3Open, getDBNameExampleROOT) {
     EXPECT_EQ(SQLITE_DBNAME_EXAMPLE_ROOT, accessor.getDBName());
     EXPECT_EQ(SQLITE_DBNAME_EXAMPLE_ROOT, accessor.getDBName());
 }
 }
 
 
-// Simple function to cound the number of records for
-// any name
+// Simple function to match records
 void
 void
 checkRecordRow(const std::string columns[],
 checkRecordRow(const std::string columns[],
                const std::string& field0,
                const std::string& field0,
@@ -518,6 +519,7 @@ protected:
     std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
     std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
     std::string add_columns[DatabaseAccessor::ADD_COLUMN_COUNT];
     std::string add_columns[DatabaseAccessor::ADD_COLUMN_COUNT];
     std::string del_params[DatabaseAccessor::DEL_PARAM_COUNT];
     std::string del_params[DatabaseAccessor::DEL_PARAM_COUNT];
+    std::string diff_params[DatabaseAccessor::DIFF_PARAM_COUNT];
 
 
     vector<const char* const*> expected_stored; // placeholder for checkRecords
     vector<const char* const*> expected_stored; // placeholder for checkRecords
     vector<const char* const*> empty_stored; // indicate no corresponding data
     vector<const char* const*> empty_stored; // indicate no corresponding data
@@ -844,4 +846,64 @@ TEST_F(SQLite3Update, concurrentTransactions) {
     accessor->commit();
     accessor->commit();
     another_accessor->commit();
     another_accessor->commit();
 }
 }
+
+//
+// Commonly(?) used data for diff related tests.  The last entry is
+// a textual representation of "version".
+//
+const char* const DIFF_ADD_TEXT = "0";
+const char* const DIFF_DELETE_TEXT = "1";
+const char* const diff_begin_data[] = {
+    "example.com.", "SOA", "3600",
+    "ns.example.com. admin.example.com. 1234 3600 1800 2419200 7200",
+    "1234", DIFF_DELETE_TEXT
+};
+const char* const diff_end_data[] = {
+    "example.com.", "SOA", "3600",
+    "ns.example.com. admin.example.com. 1300 3600 1800 2419200 7200",
+    "1300", DIFF_ADD_TEXT
+};
+
+DatabaseAccessor::DiffOperation
+textToOp(const char* const text_op) {
+    return (static_cast<DatabaseAccessor::DiffOperation>(
+                lexical_cast<int>(text_op)));
+                
+}
+
+TEST_F(SQLite3Update, addRecordDiff) {
+    uint32_t version;
+    DatabaseAccessor::DiffOperation operation;
+    zone_id = accessor->startUpdateZone("example.com.", false).second;
+
+    copy(diff_begin_data, diff_begin_data + DatabaseAccessor::DIFF_PARAM_COUNT,
+         diff_params);
+    version = lexical_cast<uint32_t>(
+        diff_begin_data[DatabaseAccessor::DIFF_PARAM_COUNT]);
+    operation =
+        textToOp(diff_begin_data[DatabaseAccessor::DIFF_PARAM_COUNT + 1]);
+    accessor->addRecordDiff(zone_id, version, operation, diff_params);
+
+    copy(diff_end_data, diff_end_data + DatabaseAccessor::DIFF_PARAM_COUNT,
+         diff_params);
+    version = lexical_cast<uint32_t>(
+        diff_end_data[DatabaseAccessor::DIFF_PARAM_COUNT]);
+    operation =
+        textToOp(diff_end_data[DatabaseAccessor::DIFF_PARAM_COUNT + 1]);
+    accessor->addRecordDiff(zone_id, version, operation, diff_params); 
+
+    accessor->commit();
+
+    vector<vector<string> > committed_diffs = accessor->getRecordDiff(zone_id);
+    expected_stored.clear();
+    expected_stored.push_back(diff_begin_data);
+    expected_stored.push_back(diff_end_data);
+    vector<vector<string> >::const_iterator it;
+    vector<const char* const*>::const_iterator eit = expected_stored.begin();
+    for (it = committed_diffs.begin(); it != committed_diffs.end(); ++it, ++eit) {
+        for (int i = 0; i < (*it).size(); ++i) {
+            EXPECT_EQ((*eit)[i], (*it)[i]);
+        }
+    }
+}
 } // end anonymous namespace
 } // end anonymous namespace

BIN
src/lib/datasrc/tests/testdata/test.sqlite3