Commit 6fd96fd3 authored by Axel Auweter's avatar Axel Auweter
Browse files

Second stage of refactoring:

* Bump cpp-driver to 2.0.1
* Create new SensorId header/source that takes over the logic
  previously found in SensorDataStore related to populating
  SensorId structs from MQTT topic strings and serializing
  them into Byte Arrays to be used as Cassandra Row Keys.
parent 60481e0b
......@@ -93,7 +93,7 @@ void mqttCallback(SimpleMQTTMessage *msg)
* the record in the database.
*/
SensorId sid;
if (mySensorDataStore->topicToSid(&sid,msg->getTopic())) {
if (sid.mqttTopicConvert(msg->getTopic())) {
#if 0
cout << "Topic decode successful:"
<< "\nRaw: " << hex << setw(16) << setfill('0') << sid.raw[0] << " " << hex << setw(16) << setfill('0') << sid.raw[1]
......
include ../config.mk
# C++ Compiler Flags (use fPIC for our dynamic library)
CXXFLAGS = -O2 -ggdb -Wall -Werror -Wno-unused-local-typedefs -Wno-unknown-warning-option\
CXXFLAGS = -O0 -ggdb -Wall -Werror \
-fPIC --std=c++11 -I$(DCDBDEPLOYPATH)/include -I./include -I./include_internal\
-I$(DCDBBASEPATH)/include/ -fmessage-length=0 -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
# List of object files to build and the derived list of corresponding source files
OBJS = src/connection.o \
src/sensordatastore.o \
src/timestamp.o
src/timestamp.o \
src/sensorid.o
# List of public header files necessary to use this libray
PUBHEADERS = $(shell find include -type f -iname "*.h")
......
......@@ -98,8 +98,21 @@ public:
*/
bool initSchema();
/**
* @brief Standard constructor for DCDBConnections.
*
* If not set explicitly, hostname and port will default to localhost and 9042.
*/
DCDBConnection();
/**
* @brief Construct a DCDBConnection to the specific host and port.
*/
DCDBConnection(std::string hostname, uint16_t port);
/**
* @brief Standard destructor for DCDBConnections.
*/
virtual ~DCDBConnection();
};
......
......@@ -16,102 +16,29 @@
#include <stdint.h>
#include <string>
#include "sensorid.h"
#include "connection.h"
#ifndef SENSORDATASTORE_H_
#define SENSORDATASTORE_H_
/* Ensure that the unions and structs are created without padding */
#pragma pack(push,1)
/**
* @brief The DeviceLocation type describes the location of a device. A
* device is the smallest piece of hardware containing sensors.
*
* The location of a device is highly specific to the system architecture
* and thus, it is only treated as unsigned 64 bit integer internally.
* Since these bits, however, make up for the location of the data within
* the distributed database, it is recommended to assign a globally used
* schema in advance leaving the higher-order bits to higher level
* entities.
*
* Example:
* ----------------------------------------------
* | 8 Bits | 8 Bits | 16 Bits | 8 Bits | ...
* ----------------------------------------------
* | Data | | | |
* | Center | Cluster | Rack | Chassis | ...
* | ID | ID | ID | ID |
* ----------------------------------------------
*/
typedef uint64_t DeviceLocation;
/**
* @brief The DeviceSensorId type describes the tuple of the sensor
* number and a unique (location-independent) device id.
* In combination with a location specified by the DeviceLocation type,
* the sensor_number defines a sensor by location.
*
* The device_id member is - in return - used to uniquely identify
* certain components, even when their location changes. A suitable
* approach is, for example, to use MAC addresses as the device_id.
*/
typedef struct {
uint64_t sensor_number : 16; /**< The sensor_number of the sensor */
uint64_t rsvd : 16; /**< Reserved */
uint64_t device_id : 32; /**< The location-independent device_id */
} DeviceSensorId;
/**
* @brief The SensorId type packs the DeviceLocation and DeviceSensorId
* types into a single object.
* In DCDB, a sensor is described by it's location, a sensor number at
* this location, and a unique part number identifier. This information
* is packed into a 128 bit wide bitfield.
*
* Access to this bitfield can be done through the raw member of through
* the two variables dl and dsid of the helper types DeviceLocation and
* DeviceSensorId.
*/
typedef union {
uint64_t raw[2]; /**< The raw bit-field representation of a sensor */
struct {
DeviceLocation dl;
DeviceSensorId dsid;
};
} SensorId;
#pragma pack(pop)
/* Forward-declaration of the implementation-internal classes */
class SensorDataStoreImpl;
class CassandraBackend;
/**
* @brief SensorDataStore is the "main" class of the DCDBLib library.
*
* Use this class to initialize, write, and read sensor data.
* @brief SensorDataStore is the class of the DCDBLib library
* to write and read sensor data.
*/
class SensorDataStore
{
private:
SensorDataStoreImpl* impl;
CassandraBackend* csBackend;
public:
/**
* @brief This function populates a preallocated SensorId object
* from a MQTT topic string.
* @param sid A pre-allocated SensorId object.
* @param topic The string from which the SensorId object will be populated.
* @return Returns true if the topic string was valid and the SensorId object was populated.
*/
bool topicToSid(SensorId* sid, std::string topic);
/**
* @brief This function inserts a single sensor reading into
* the database.
* @param sid A SensorId object (typically the result of calling topicToSid()).
* @param sid A SensorId object.
* @param ts The timestamp of the sensor reading.
* @param value The value of the sensor reading.
*/
......@@ -127,6 +54,8 @@ public:
* @brief A shortcut constructor for a SensorDataStore object
* that allows accessing the data store through a
* connection that is already established.
* @param conn The DCDBConnection object of an established
* connection to Cassandra.
*/
SensorDataStore(DCDBConnection* conn);
......
/*
* sensorid.h
*
* Created on: May 18, 2015
* Author: Axel Auweter
*/
#include <cstdint>
#include <string>
#ifndef SENSORID_H
#define SENSORID_H
/* Ensure that the unions and structs are created without padding */
#pragma pack(push,1)
/**
* @brief The DeviceLocation type describes the location of a device. A
* device is the smallest piece of hardware containing sensors.
*
* The location of a device is highly specific to the system architecture
* and thus, it is only treated as unsigned 64 bit integer internally.
* Since these bits, however, make up for the location of the data within
* the distributed database, it is recommended to assign a globally used
* schema in advance leaving the higher-order bits to higher level
* entities.
*
* Example:
* ----------------------------------------------
* | 8 Bits | 8 Bits | 16 Bits | 8 Bits | ...
* ----------------------------------------------
* | Data | | | |
* | Center | Cluster | Rack | Chassis | ...
* | ID | ID | ID | ID |
* ----------------------------------------------
*/
typedef uint64_t DeviceLocation;
/**
* @brief The DeviceSensorId type describes the tuple of the sensor
* number and a unique (location-independent) device id.
* In combination with a location specified by the DeviceLocation type,
* the sensor_number defines a sensor by location.
*
* The device_id member is - in return - used to uniquely identify
* certain components, even when their location changes. A suitable
* approach is, for example, to use MAC addresses as the device_id.
*/
typedef struct {
uint64_t sensor_number : 16; /**< The sensor_number of the sensor */
uint64_t rsvd : 16; /**< Reserved */
uint64_t device_id : 32; /**< The location-independent device_id */
} DeviceSensorId;
/**
* @brief The SensorId class packs the DeviceLocation and DeviceSensorId
* types into a single object.
*
* In DCDB, a sensor is described by it's location, a sensor number at
* this location, and a unique part number identifier. This information
* is packed into a 128 bit wide bitfield.
*
* Access to this bitfield can be done through the raw member of through
* the two variables dl and dsid of the helper types DeviceLocation and
* DeviceSensorId.
*/
class SensorId {
protected:
union {
uint64_t raw[2]; /**< The raw bit-field representation of a sensor */
struct {
DeviceLocation dl;
DeviceSensorId dsid;
};
} data;
public:
DeviceLocation getDeviceLocation();
void setDeviceLocation(DeviceLocation dl);
DeviceSensorId getDeviceSensorId();
void setDeviceSensorId(DeviceSensorId dsid);
uint16_t getSensorNumber();
void setSensorNumber(uint16_t sn);
uint16_t getRsvd();
void setRsvd(uint16_t rsvd);
uint32_t getDeviceId();
void setDeviceId(uint32_t did);
uint64_t* getRaw();
void setRaw(uint64_t* raw);
/**
* @brief This function populates the data field from a MQTT topic string.
* @param topic The string from which the SensorId object will be populated.
* @return Returns true if the topic string was valid and the data field of the object was populated.
*/
bool mqttTopicConvert(std::string mqttTopic);
/**
* @brief This function returns a "key" string which
* corresponds to the supplied SensorId object.
* @return Returns the serialized string that can be used by Cassandra as row key.
*/
std::string serialize();
SensorId();
SensorId(std::string mqttTopic);
virtual ~SensorId();
};
#pragma pack(pop)
#endif /* SENSORID_H */
......@@ -32,14 +32,6 @@ protected:
CassSession* session; /**< The CassSession object given by the connection. */
const CassPrepared* preparedInsert; /**< The prepared statement for fast insertions. */
/**
* @brief This function returns a "key" string which
* corresponds to the supplied SensorId object.
* @param sid The SensorId object to convert
* @return Returns the serialized string that can be used by Cassandra as row key.
*/
std::string sidConvert(SensorId *sid);
/**
* @brief Prepare for insertions.
* @param ttl A TTL that will be set for newly inserted values. Set to 0 to insert without TTL.
......@@ -47,13 +39,6 @@ protected:
void prepareInsert(uint64_t ttl);
public:
/**
* @brief This function converts a MQTT topic string to a SensorId object
* @param topic The MQTT topic string to convert
* @param sid A preallocated SensorId object to fill
*/
bool topicToSid(SensorId* sid, std::string topic);
/**
* @brief This function inserts a sensor reading into the database
* @param sid The SensorId object representing the sensor (typically obtained from topicToSid)
......
......@@ -43,20 +43,6 @@
#include "dcdbendian.h"
/**
* @details
* This function serializes a SensorId object into a
* big-endian 128-bit character array represented as
* std::string.
*/
std::string SensorDataStoreImpl::sidConvert(SensorId *sid)
{
uint64_t ll[2];
ll[0] = Endian::hostToBE(sid->raw[0]);
ll[1] = Endian::hostToBE(sid->raw[1]);
return std::string((char*)ll, 16);
}
/**
* @details
* Since we want high-performance inserts, we prepare the
......@@ -102,44 +88,6 @@ void SensorDataStoreImpl::prepareInsert(uint64_t ttl)
}
}
/**
* @details
* The conversion of a MQTT message topic to a SensorId
* object is performed by byte-wise scanning of the string,
* and skipping of all characters except for those in the
* range [0-9,a-f,A-F]. Each character is then turned from
* hex string into its binary representation an OR'ed into
* the 128-bit raw fields of the SensorId object.
*
* Applications should not call this function directly, but
* use the topicToSid function provided by the
* SensorDataStore class.
*/
bool SensorDataStoreImpl::topicToSid(SensorId* sid, std::string topic)
{
uint64_t pos = 0;
const char* buf = topic.c_str();
sid->raw[0] = 0;
sid->raw[1] = 0;
while (*buf && pos < 128) {
if (*buf >= '0' && *buf <= '9') {
sid->raw[pos / 64] |= (((uint64_t)(*buf - '0')) << (60-(pos%64)));
pos += 4;
}
else if (*buf >= 'A' && *buf <= 'F') {
sid->raw[pos / 64] |= (((uint64_t)(*buf - 'A' + 0xa)) << (60-(pos%64)));
pos += 4;
}
else if (*buf >= 'a' && *buf <= 'f') {
sid->raw[pos / 64] |= (((uint64_t)(*buf - 'a' + 0xa)) << (60-(pos%64)));
pos += 4;
}
buf++;
}
return pos == 128;
}
/**
* @details
* To insert a sensor reading, the Rsvd field of the SensorId must
......@@ -162,10 +110,10 @@ void SensorDataStoreImpl::insert(SensorId* sid, uint64_t ts, uint64_t value)
/* Calculate and insert week number */
uint16_t week = ts / 604800000000000;
sid->dsid.rsvd = week;
sid->setRsvd(week);
/* Insert into Cassandra */
std::string key = sidConvert(sid);
std::string key = sid->serialize();
CassError rc = CASS_OK;
CassStatement* statement = NULL;
......@@ -221,17 +169,6 @@ SensorDataStoreImpl::~SensorDataStoreImpl()
connection = nullptr;
}
/**
* @details
* Instead of doing the actual work, this function simply
* forwards to the insert function of the SensorDataStoreImpl
* class.
*/
bool SensorDataStore::topicToSid(SensorId* sid, std::string topic)
{
return impl->topicToSid(sid, topic);
}
/**
* @details
* Instead of doing the actual work, this function simply
......
/*
* sensorid.cpp
*
* Created on: May 18, 2015
* Author: Axel Auweter
*/
#include "sensorid.h"
#include "dcdbendian.h"
/*
* Public Functions
*/
DeviceLocation SensorId::getDeviceLocation()
{
return data.dl;
}
void SensorId::setDeviceLocation(DeviceLocation dl)
{
data.dl = dl;
}
DeviceSensorId SensorId::getDeviceSensorId()
{
return data.dsid;
}
void SensorId::setDeviceSensorId(DeviceSensorId dsid)
{
/* Do not overwrite the RSVD field */
data.dsid.sensor_number = dsid.sensor_number;
data.dsid.device_id = dsid.device_id;
}
uint16_t SensorId::getSensorNumber()
{
return data.dsid.sensor_number;
}
void SensorId::setSensorNumber(uint16_t sn)
{
data.dsid.sensor_number = sn;
}
uint16_t SensorId::getRsvd()
{
return data.dsid.rsvd;
}
void SensorId::setRsvd(uint16_t rsvd)
{
data.dsid.rsvd = rsvd;
}
uint32_t SensorId::getDeviceId()
{
return data.dsid.device_id;
}
void SensorId::setDeviceId(uint32_t did)
{
data.dsid.device_id = did;
}
uint64_t* SensorId::getRaw()
{
return data.raw;
}
void SensorId::setRaw(uint64_t* raw)
{
data.raw[0] = raw[0];
data.raw[1] = raw[1];
}
/**
* @details
* The conversion of a MQTT message topic to a SensorId
* object is performed by byte-wise scanning of the string,
* and skipping of all characters except for those in the
* range [0-9,a-f,A-F]. Each character is then turned from
* hex string into its binary representation an OR'ed into
* the 128-bit raw fields of the SensorId object.
*/
bool SensorId::mqttTopicConvert(std::string mqttTopic)
{
uint64_t pos = 0;
const char* buf = mqttTopic.c_str();
data.raw[0] = 0;
data.raw[1] = 0;
while (*buf && pos < 128) {
if (*buf >= '0' && *buf <= '9') {
data.raw[pos / 64] |= (((uint64_t)(*buf - '0')) << (60-(pos%64)));
pos += 4;
}
else if (*buf >= 'A' && *buf <= 'F') {
data.raw[pos / 64] |= (((uint64_t)(*buf - 'A' + 0xa)) << (60-(pos%64)));
pos += 4;
}
else if (*buf >= 'a' && *buf <= 'f') {
data.raw[pos / 64] |= (((uint64_t)(*buf - 'a' + 0xa)) << (60-(pos%64)));
pos += 4;
}
buf++;
}
return pos == 128;
}
/**
* @details
* This function serializes a SensorId object into a
* big-endian 128-bit character array represented as
* std::string.
*/
std::string SensorId::serialize()
{
uint64_t ll[2];
ll[0] = Endian::hostToBE(data.raw[0]);
ll[1] = Endian::hostToBE(data.raw[1]);
return std::string((char*)ll, 16);
}
SensorId::SensorId()
{
/* Initialize to zeros */
data.raw[0] = 0;
data.raw[1] = 0;
}
SensorId::SensorId(std::string mqttTopic)
{
/* Try to convert from MQTT topic */
if (!mqttTopicConvert(mqttTopic)) {
/* Fall back to zeros */
data.raw[0] = 0;
data.raw[1] = 0;
}
}
SensorId::~SensorId()
{
/* Nothing to do here */
}
......@@ -8,7 +8,7 @@ MOSQUITTO_VERSION = 1.3.5
BOOST_VERSION = 1.57.0
SNMP_VERSION = 5.7.3
OPENSSL_VERSION = 1.0.1m
CPPDRV_VERSION = 2.0.0
CPPDRV_VERSION = 2.0.1
LIBUV_VERSION = 0.10.32
BOOST_VERSION_U = $(subst .,_,$(BOOST_VERSION))
......@@ -267,11 +267,12 @@ $(DCDBDEPSPATH)/.prerequesites: $(DCDBDEPSPATH)/.extract-distfiles
fi; \
mkdir -p $(DCDBDEPSPATH)/cpp-driver_build; \
cd $(DCDBDEPSPATH)/cpp-driver_build && \
cmake --debug-output $(CMAKE_CROSS_FLAGS) \
cmake $(CMAKE_CROSS_FLAGS) \
-DCMAKE_CXX_FLAGS="$(CXX11FLAGS) -Wno-unused-command-line-argument -L$(DCDBDEPLOYPATH)/lib " \
-DOPENSSL_ROOT_DIR=$(DCDBDEPLOYPATH)/ \
-DLIBUV_ROOT_DIR=$(DCDBDEPLOYPATH)/ \
-DCASS_BUILD_EXAMPLES=NO \
-DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_INSTALL_PREFIX=$(DCDBDEPLOYPATH)/ \
-DCMAKE_EXE_LINKER_FLAGS="-L$(DCDBDEPLOYPATH)/lib -lboost_random" \
-DCMAKE_SHARED_LINKER_FLAGS="-L$(DCDBDEPLOYPATH)/lib -lboost_random" \
......
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