Commit d4c441f4 authored by Razvan Becheriu's avatar Razvan Becheriu

refactored cassandra backend and fixed issues

parent c164ebc2
......@@ -42,3 +42,6 @@ config.h.in~
/local.zone.sqlite3
/logger_lockfile
/report.info
*.clang_complete
*.dirstamp
......@@ -13,6 +13,7 @@ endif
if HAVE_CQL
SHTESTS += cql_tests.sh
endif
noinst_SCRIPTS = $(SHTESTS)
EXTRA_DIST = dhcpdb_create_1.0.mysql
......
......@@ -235,8 +235,6 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
}
}
return (answer);
}
......
......@@ -733,7 +733,5 @@ ParserContextPtr& globalContext() {
return (global_context_ptr);
}
}; // end of isc::dhcp namespace
}; // end of isc namespace
......@@ -73,6 +73,10 @@ void configure(const std::string& file_name) {
Daemon::configureLogger(json->get("Logging"),
CfgMgr::instance().getStagingCfg());
// Apply the new logger configuration to log4cplus. It is done before
// commit in case something goes wrong.
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
// Get Dhcp4 component from the config
dhcp4 = json->get("Dhcp4");
if (!dhcp4) {
......@@ -101,11 +105,6 @@ void configure(const std::string& file_name) {
isc_throw(isc::BadValue, reason);
}
// If configuration was parsed successfully, apply the new logger
// configuration to log4cplus. It is done before commit in case
// something goes wrong.
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
// Use new configuration.
/// @todo: This commit should be moved to
/// CtrlDhcp4Srv::commandConfigReloadHandler.
......
......@@ -171,8 +171,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
return (answer);
}
} catch (const std::exception& ex) {
return (isc::config::createAnswer(1, "Failed to process configuration:"
+ string(ex.what())));
return (isc::config::createAnswer(1, "Failed to process configuration:" +
string(ex.what())));
}
// Re-open lease and host database with new parameters.
......@@ -182,8 +182,8 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
cfg_db->createManagers();
} catch (const std::exception& ex) {
return (isc::config::createAnswer(1, "Unable to open database: "
+ std::string(ex.what())));
return (isc::config::createAnswer(1, "Unable to open database: " +
std::string(ex.what())));
}
// Regenerate server identifier if needed.
......
......@@ -79,6 +79,10 @@ void configure(const std::string& file_name) {
Daemon::configureLogger(json->get("Logging"),
CfgMgr::instance().getStagingCfg());
// Apply the new logger configuration to log4cplus. It is done before
// commit in case something goes wrong.
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
// Get Dhcp6 component from the config
dhcp6 = json->get("Dhcp6");
......@@ -108,11 +112,6 @@ void configure(const std::string& file_name) {
isc_throw(isc::BadValue, reason);
}
// If configuration was parsed successfully, apply the new logger
// configuration to log4cplus. It is done before commit in case
// something goes wrong.
CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
// Use new configuration.
CfgMgr::instance().commit();
......
/perfdhcp
/perfdhcp.1
/perfdhcp.8
......@@ -127,6 +127,7 @@ libkea_dhcpsrv_la_SOURCES += logging.cc logging.h
libkea_dhcpsrv_la_SOURCES += logging_info.cc logging_info.h
libkea_dhcpsrv_la_SOURCES += memfile_lease_mgr.cc memfile_lease_mgr.h
libkea_dhcpsrv_la_SOURCES += memfile_lease_storage.h
libkea_dhcpsrv_la_SOURCES += sql_common.h
if HAVE_MYSQL
libkea_dhcpsrv_la_SOURCES += mysql_lease_mgr.cc mysql_lease_mgr.h
......@@ -141,10 +142,13 @@ libkea_dhcpsrv_la_SOURCES += pgsql_connection.cc pgsql_connection.h
libkea_dhcpsrv_la_SOURCES += pgsql_exchange.cc pgsql_exchange.h
libkea_dhcpsrv_la_SOURCES += pgsql_lease_mgr.cc pgsql_lease_mgr.h
endif
if HAVE_CQL
libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
libkea_dhcpsrv_la_SOURCES += cql_connection.cc cql_connection.h
libkea_dhcpsrv_la_SOURCES += cql_exchange.cc cql_exchange.h
libkea_dhcpsrv_la_SOURCES += cql_lease_mgr.cc cql_lease_mgr.h
endif
libkea_dhcpsrv_la_SOURCES += pool.cc pool.h
libkea_dhcpsrv_la_SOURCES += srv_config.cc srv_config.h
libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h
......
......@@ -19,6 +19,7 @@
#include <dhcpsrv/database_connection.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/cql_exchange.h>
#include <inttypes.h>
#include <cassandra.h>
#include <vector>
......@@ -26,17 +27,6 @@
namespace isc {
namespace dhcp {
/// @brief Defines a single query
///
/// @param params_ Bind parameter names
/// @param name_ Short name of the query.
/// @param text_ Text representation of the actual query.
struct CqlTaggedStatement {
const char** params_;
const char* name_;
const char* text_;
};
// Defines CQL backend version: 2.3
const uint32_t CQL_DRIVER_VERSION_MAJOR = CASS_VERSION_MAJOR;
const uint32_t CQL_DRIVER_VERSION_MINOR = CASS_VERSION_MINOR;
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
#include <dhcp/hwaddr.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/cql_connection.h>
#include <dhcpsrv/cql_exchange.h>
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
#include <cassandra.h>
......@@ -28,35 +29,6 @@
namespace isc {
namespace dhcp {
/// @brief Structure used to bind C++ input values to dynamic SQL parameters
/// The structure contains a vector which store the input values,
/// This vector is passed directly into the
/// CQL execute call.
///
/// Note that the data values are stored as pointers. These pointers need
/// to be valid for the duration of the CQL statement execution. In other
/// words populating them with pointers to values that go out of scope
/// before statement is executed is a bad idea.
struct CqlDataArray {
/// Add void pointer to a vector of pointers to the data values.
std::vector<void*> values_;
void add(void* value) {
values_.push_back(value);
}
/// Remove void pointer from a vector of pointers to the data values.
void remove(int index) {
if (values_.size() <= index) {
isc_throw(BadValue, "Index " << index << " out of bounds: [0, " <<
(values_.size() - 1) << "]");
}
values_.erase(values_.begin() + index);
}
/// Get size.
size_t size() {
return values_.size();
}
};
class CqlVersionExchange;
class CqlLeaseExchange;
class CqlLease4Exchange;
......@@ -71,12 +43,11 @@ public:
// Time conversion methods.
static void
convertToDatabaseTime(const time_t& cltt,
const uint32_t& valid_lifetime,
uint64_t& expire) {
const cass_int64_t& valid_lifetime,
cass_int64_t& expire) {
// Calculate expiry time. Store it in the 64-bit value so as we can
// detect overflows.
int64_t expire_time = static_cast<int64_t>(cltt) +
static_cast<int64_t>(valid_lifetime);
cass_int64_t expire_time = static_cast<cass_int64_t>(cltt) + valid_lifetime;
if (expire_time > DatabaseConnection::MAX_DB_TIME) {
isc_throw(BadValue, "Time value is too large: " << expire_time);
......@@ -86,11 +57,11 @@ public:
}
static void
convertFromDatabaseTime(const uint64_t& expire,
const uint32_t& valid_lifetime,
convertFromDatabaseTime(const cass_int64_t& expire,
const cass_int64_t& valid_lifetime,
time_t& cltt) {
// Convert to local time
cltt = expire - static_cast<int64_t>(valid_lifetime);
cltt = static_cast<time_t>(expire - valid_lifetime);
}
};
......@@ -281,7 +252,7 @@ public:
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual Lease6Collection getLeases6(Lease::Type type, const DUID& duid,
uint32_t iaid) const;
uint32_t iaid) const;
/// @brief Returns existing IPv6 lease for a given DUID+IA combination
///
......@@ -308,8 +279,8 @@ public:
/// by the database backend are added.
/// @param max_leases A maximum number of leases to be returned. If this
/// value is set to 0, all expired (but not reclaimed) leases are returned.
virtual void getExpiredLeases6(Lease6Collection& ,
const size_t ) const;
virtual void getExpiredLeases6(Lease6Collection& expired_leases,
const size_t max_leases) const;
/// @brief Returns a collection of expired DHCPv4 leases.
///
......@@ -321,8 +292,8 @@ public:
/// by the database backend are added.
/// @param max_leases A maximum number of leases to be returned. If this
/// value is set to 0, all expired (but not reclaimed) leases are returned.
virtual void getExpiredLeases4(Lease4Collection& ,
const size_t ) const;
virtual void getExpiredLeases4(Lease4Collection& expired_leases,
const size_t max_leases) const;
/// @brief Updates IPv4 lease.
///
......@@ -368,7 +339,7 @@ public:
/// time will not be deleted.
///
/// @return Number of leases deleted.
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t );
virtual uint64_t deleteExpiredReclaimedLeases4(const uint32_t secs);
/// @brief Deletes all expired and reclaimed DHCPv6 leases.
///
......@@ -377,7 +348,7 @@ public:
/// time will not be deleted.
///
/// @return Number of leases deleted.
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t );
virtual uint64_t deleteExpiredReclaimedLeases6(const uint32_t secs);
/// @brief Return backend type
///
......@@ -405,7 +376,7 @@ public:
///
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
virtual std::pair<uint32_t, uint32_t> getVersion() const;
virtual std::pair<unsigned int, unsigned int> getVersion() const;
/// @brief Commit Transactions
///
......@@ -444,43 +415,6 @@ public:
NUM_STATEMENTS // Number of statements
};
/// @brief Binds data specified in data
///
/// This method calls one of cass_value_bind_{none,bool,int32,int64,string,bytes}.
/// It is used to bind C++ data types used by Kea into formats used by Cassandra.
///
/// @param statement Statement object representing the query
/// @param stindex Index of statement being executed
/// @param data array that has been created for the type of lease in question.
/// @param exchange Exchange object to use
static void bindData(CassStatement* statement, const StatementIndex stindex,
CqlDataArray& data, const SqlExchange& exchange);
/// @brief Returns type of data for specific parameter.
///
/// Returns type of a given parameter of a given statement.
///
/// @param stindex Index of statement being executed.
/// @param pindex Index of the parameter for a given statement.
/// @param exchange Exchange object to use
static ExchangeDataType getDataType(const StatementIndex stindex, int pindex,
const SqlExchange& exchange);
/// @brief Retrieves data returned by Cassandra.
///
/// This method calls one of cass_value_get_{none,bool,int32,int64,string,bytes}.
/// It is used to retrieve data returned by Cassandra into standard C++ types
/// used by Kea.
///
/// @param row row of data returned by CQL library
/// @param pindex Index of statement being executed
/// @param data array that has been created for the type of lease in question.
/// @param size a structure that holds information about size
/// @param dindex data index (specifies which entry in size array is used)
/// @param exchange Exchange object to use
static void getData(const CassRow* row, const int pindex, CqlDataArray& data,
CqlDataArray& size, const int dindex, const SqlExchange& exchange);
private:
/// @brief Add Lease Common Code
......@@ -500,7 +434,7 @@ private:
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
bool addLeaseCommon(StatementIndex stindex, CqlDataArray& data,
CqlLeaseExchange& exchange);
CqlLeaseExchange& exchange);
/// @brief Get Lease Collection Common Code
///
......@@ -645,7 +579,7 @@ private:
/// @throw isc::dhcp::DbOperationError An operation on the open database has
/// failed.
bool deleteLeaseCommon(StatementIndex stindex, CqlDataArray& data,
CqlLeaseExchange& exchange);
CqlLeaseExchange& exchange);
/// @brief Delete expired-reclaimed leases.
///
......@@ -659,6 +593,20 @@ private:
uint64_t deleteExpiredReclaimedLeasesCommon(const uint32_t secs,
StatementIndex statement_index);
/// @brief Check if CQL statement has been applied.
///
/// @param future
/// @param exchange
/// @param row_count
/// @param column_count
///
/// @return true if statement has been succesfully applied,
/// false otherwise
static bool hasStatementBeenApplied(CassFuture* future,
CqlLeaseExchange& exchange,
size_t* row_count = NULL,
size_t* column_count = NULL);
/// CQL queries used by CQL backend
static CqlTaggedStatement tagged_statements_[];
/// Database connection object
......
......@@ -595,7 +595,7 @@ with the specified address to the PostgreSQL backend database.
A debug message issued when the server is about to add an IPv6 lease
with the specified address to the PostgreSQL backend database.
% DHCPSRV_PGSQL_COMMIT committing to MySQL database
% DHCPSRV_PGSQL_COMMIT committing to PostgreSQL database
The code has issued a commit call. All outstanding transactions will be
committed to the database. Note that depending on the PostgreSQL settings,
the committal may not include a write to disk.
......
......@@ -15,6 +15,7 @@
#include <dhcpsrv/lease.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/db_exceptions.h>
#include <dhcpsrv/sql_common.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
......@@ -60,92 +61,6 @@
namespace isc {
namespace dhcp {
/// @brief Used to map server data types with internal backend storage data
/// types.
enum ExchangeDataType {
EXCHANGE_DATA_TYPE_NONE,
EXCHANGE_DATA_TYPE_BOOL,
EXCHANGE_DATA_TYPE_INT32,
EXCHANGE_DATA_TYPE_INT64,
EXCHANGE_DATA_TYPE_TIMESTAMP,
EXCHANGE_DATA_TYPE_STRING,
EXCHANGE_DATA_TYPE_BYTES
};
/// @brief Used to specify the direction of the data exchange between the
/// database and the server.
enum ExchangeDataTypeIO {
EXCHANGE_DATA_TYPE_IO_IN,
EXCHANGE_DATA_TYPE_IO_OUT,
EXCHANGE_DATA_TYPE_IO_IN_OUT
};
/// @brief Used to map the column name with internal backend storage data types.
struct ExchangeColumnInfo {
ExchangeColumnInfo () : name_(""), index_(0), type_io_(EXCHANGE_DATA_TYPE_IO_IN),
type_(EXCHANGE_DATA_TYPE_NONE) {};
ExchangeColumnInfo (const char* name, const uint32_t index,
const ExchangeDataTypeIO type_io, const ExchangeDataType type) :
name_(name), index_(index), type_io_(type_io), type_(type) {};
std::string name_;
uint32_t index_;
ExchangeDataTypeIO type_io_;
ExchangeDataType type_;
};
typedef boost::shared_ptr<ExchangeColumnInfo> ExchangeColumnInfoPtr;
typedef boost::multi_index_container<
// Container comprises elements of ExchangeColumnInfoPtr type.
ExchangeColumnInfoPtr,
// Here we start enumerating various indexes.
boost::multi_index::indexed_by<
// Sequenced index allows accessing elements in the same way as elements
// in std::list.
// Sequenced is an index #0.
boost::multi_index::sequenced<>,
// Start definition of index #1.
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
ExchangeColumnInfo,
std::string,
&ExchangeColumnInfo::name_
>
>,
// Start definition of index #2.
boost::multi_index::hashed_non_unique<
boost::multi_index::member<
ExchangeColumnInfo,
uint32_t,
&ExchangeColumnInfo::index_
>
>
>
> ExchangeColumnInfoContainer;
/// Pointer to the ExchangeColumnInfoContainer object.
typedef boost::shared_ptr<ExchangeColumnInfoContainer> ExchangeColumnInfoContainerPtr;
/// Type of the index #1 - name.
typedef ExchangeColumnInfoContainer::nth_index<1>::type ExchangeColumnInfoContainerName;
/// Pair of iterators to represent the range of ExchangeColumnInfo having the
/// same name value. The first element in this pair represents
/// the beginning of the range, the second element represents the end.
typedef std::pair<ExchangeColumnInfoContainerName::const_iterator,
ExchangeColumnInfoContainerName::const_iterator> ExchangeColumnInfoContainerNameRange;
/// Type of the index #2 - index.
typedef ExchangeColumnInfoContainer::nth_index<2>::type ExchangeColumnInfoContainerIndex;
/// Pair of iterators to represent the range of ExchangeColumnInfo having the
/// same index value. The first element in this pair represents
/// the beginning of the range, the second element represents the end.
typedef std::pair<ExchangeColumnInfoContainerIndex::const_iterator,
ExchangeColumnInfoContainerIndex::const_iterator> ExchangeColumnInfoContainerIndexRange;
class SqlExchange {
public:
SqlExchange () {};
virtual ~SqlExchange() {};
ExchangeColumnInfoContainer parameters_; ///< Column names and types
};
/// @brief Abstract Lease Manager
///
/// This is an abstract API for lease database backends. It provides unified
......
......@@ -124,7 +124,6 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
} else {
cfg_db->setHostDbAccessString(getDbAccessString());
}
}
// Create the database access string
......
......@@ -12,11 +12,16 @@
#include <boost/scoped_ptr.hpp>
#include <vector>
#include <stdint.h>
namespace isc {
namespace dhcp {
/// Defines PostgreSQL backend version: 3.0
const uint32_t PG_SCHEMA_VERSION_MAJOR = 3;
const uint32_t PG_SCHEMA_VERSION_MINOR = 0;
// Maximum number of parameters that can be used a statement
// @todo This allows us to use an initializer list (since we can't
// require C++11). It's unlikely we'd go past this many a single
......@@ -57,6 +62,7 @@ const size_t OID_INT2 = 21; // 2 byte int
const size_t OID_TIMESTAMP = 1114;
const size_t OID_VARCHAR = 1043;
//@}
/// @brief RAII wrapper for Posgtresql Result sets
......
......@@ -214,7 +214,6 @@ namespace dhcp {
/// database.
class PgSqlLeaseExchange : public PgSqlExchange {
public:
PgSqlLeaseExchange()
: addr_str_(""), valid_lifetime_(0), valid_lft_str_(""),
expire_(0), expire_str_(""), subnet_id_(0), subnet_id_str_(""),
......@@ -714,7 +713,7 @@ PgSqlLeaseMgr::PgSqlLeaseMgr(const DatabaseConnection::ParameterMap& parameters)
<< " does not match expected count:" << NUM_STATEMENTS);
}
pair<uint32_t, uint32_t> code_version(PG_CURRENT_VERSION, PG_CURRENT_MINOR);
pair<uint32_t, uint32_t> code_version(PG_SCHEMA_VERSION_MAJOR, PG_SCHEMA_VERSION_MINOR);
pair<uint32_t, uint32_t> db_version = getVersion();
if (code_version != db_version) {
isc_throw(DbOpenError, "Posgresql schema version mismatch: need version: "
......@@ -729,8 +728,8 @@ PgSqlLeaseMgr::~PgSqlLeaseMgr() {
std::string
PgSqlLeaseMgr::getDBVersion() {
std::stringstream tmp;
tmp << "PostgreSQL backend " << PG_CURRENT_VERSION;
tmp << "." << PG_CURRENT_MINOR;
tmp << "PostgreSQL backend " << PG_SCHEMA_VERSION_MAJOR;
tmp << "." << PG_SCHEMA_VERSION_MINOR;
tmp << ", library " << PQlibVersion();
return (tmp.str());
}
......
......@@ -25,10 +25,6 @@ namespace dhcp {
class PgSqlLease4Exchange;
class PgSqlLease6Exchange;
/// Defines PostgreSQL backend version: 3.0
const uint32_t PG_CURRENT_VERSION = 3;
const uint32_t PG_CURRENT_MINOR = 0;
/// @brief PostgreSQL Lease Manager
///
/// This class provides the \ref isc::dhcp::LeaseMgr interface to the PostgreSQL
......
......@@ -376,7 +376,7 @@ TEST_F(CqlLeaseMgrTest, getType) {
TEST_F(CqlLeaseMgrTest, checkTimeConversion) {
const time_t cltt = time(NULL);
const uint32_t valid_lft = 86400; // 1 day
uint64_t cql_expire;
cass_int64_t cql_expire;
// Convert to the database time
CqlExchange::convertToDatabaseTime(cltt, valid_lft, cql_expire);
......
......@@ -190,8 +190,8 @@ TEST_F(PgSqlLeaseMgrTest, checkVersion) {
// Check version
pair<uint32_t, uint32_t> version;
ASSERT_NO_THROW(version = lmptr_->getVersion());
EXPECT_EQ(PG_CURRENT_VERSION, version.first);
EXPECT_EQ(PG_CURRENT_MINOR, version.second);
EXPECT_EQ(PG_SCHEMA_VERSION_MAJOR, version.first);
EXPECT_EQ(PG_SCHEMA_VERSION_MINOR, version.second);
}
////////////////////////////////////////////////////////////////////////////////
......
......@@ -241,6 +241,6 @@ public:
}
#endif // EXCEPTIONS_H
// Local Variables:
// Local Variables:
// mode: c++
// End:
// End:
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