Commit 0ea04c4b authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

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

adding diffs.
parent 09e4d880
......@@ -113,6 +113,20 @@ public:
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
*
......@@ -453,6 +467,14 @@ public:
/// to the method or internal database error.
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.
///
/// Each derived class implementation of this method will create a new
......
......@@ -52,7 +52,9 @@ enum StatementID {
DEL_RECORD = 8,
ITERATE = 9,
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] = {
......@@ -81,7 +83,12 @@ const char* const text_statements[NUM_STATEMENTS] = {
*/
"SELECT name FROM records " // FIND_PREVIOUS
"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 {
......@@ -206,6 +213,11 @@ const char* const SCHEMA_LIST[] = {
"ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
"rdata STRING NOT NULL)",
"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
};
......@@ -214,7 +226,7 @@ prepare(sqlite3* const db, const char* const statement) {
sqlite3_stmt* prepared = NULL;
if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) {
isc_throw(SQLite3Error, "Could not prepare SQLite statement: " <<
statement);
statement << ": " << sqlite3_errmsg(db));
}
return (prepared);
}
......@@ -681,6 +693,62 @@ SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
*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
SQLite3Accessor::findPreviousName(int zone_id, const std::string& rname)
const
......
......@@ -157,6 +157,14 @@ public:
virtual void deleteRecordInZone(
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
/// with a fixed prefix of "sqlite3_" followed by the DB file name
/// removing any path name. For example, for the DB file
......
......@@ -233,6 +233,8 @@ public:
virtual void rollback() {}
virtual void addRecordToZone(const string (&)[ADD_COLUMN_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 {
return (database_name_);
......
......@@ -22,6 +22,7 @@
#include <dns/rrclass.h>
#include <gtest/gtest.h>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <fstream>
#include <sqlite3.h>
......@@ -29,6 +30,7 @@
using namespace std;
using namespace isc::datasrc;
using boost::shared_ptr;
using boost::lexical_cast;
using isc::data::ConstElementPtr;
using isc::data::Element;
using isc::dns::RRClass;
......@@ -214,8 +216,7 @@ TEST(SQLite3Open, getDBNameExampleROOT) {
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
checkRecordRow(const std::string columns[],
const std::string& field0,
......@@ -518,6 +519,7 @@ protected:
std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
std::string add_columns[DatabaseAccessor::ADD_COLUMN_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*> empty_stored; // indicate no corresponding data
......@@ -844,4 +846,64 @@ TEST_F(SQLite3Update, concurrentTransactions) {
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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment