DatabaseCampaign: abstract campain for interaction with MySQL Database
The DatabaseCampaign interacts with the MySQL tables that are created
by the import-trace and prune-trace tools. It does offer all
unfinished experiment pilots from the database to the
fail-clients. Those clients send back a (by the experiment) defined
protobuf message as a result. The custom protobuf message does have to
need the form:
import "DatabaseCampaignMessage.proto";
message ExperimentMsg {
required DatabaseCampaignMessage fsppilot = 1;
repeated group Result = 2 {
// custom fields
required int32 bitoffset = 1;
optional int32 result = 2;
}
}
The DatabaseCampaignMessage is the pilot identifier from the
database. For each of the repeated result entries a row in a table is
allocated. The structure of this table is constructed (by protobuf
reflection) from the description of the message. Each field in the
Result group becomes a column in the result table. For the given
example it would be:
CREATE TABLE result_ExperimentMessage(
pilot_id INT,
bitoffset INT NOT NULL,
result INT,
PRIMARY_KEY(pilot_id)
)
Change-Id: I28fb5488e739d4098b823b42426c5760331027f8
This commit is contained in:
206
src/core/util/DatabaseProtobufAdapter.hpp
Normal file
206
src/core/util/DatabaseProtobufAdapter.hpp
Normal file
@ -0,0 +1,206 @@
|
||||
#ifndef __COMM_PROTOBUF_DATABASE_ADAPTER_H__
|
||||
#define __COMM_PROTOBUF_DATABASE_ADAPTER_H__
|
||||
|
||||
#include <vector>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include "DatabaseCampaignMessage.pb.h"
|
||||
#include "util/Database.hpp"
|
||||
#include "util/StringJoiner.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace fail {
|
||||
|
||||
class DatabaseProtobufAdapter {
|
||||
Database *db;
|
||||
MYSQL_STMT *stmt;
|
||||
|
||||
void error_create_table();
|
||||
|
||||
/** \class TypeBridge
|
||||
A type bridge bridges the gap between a protobuf type and the
|
||||
sql database. It defines how the result table is defined, and
|
||||
how the message types are mapped onto SQL types. The whole
|
||||
message is mapped into a top level TypeBridge_message */
|
||||
struct TypeBridge {
|
||||
bool primary_key; // !< Should the field be put into the
|
||||
// !< primary key
|
||||
const google::protobuf::FieldDescriptor *desc;
|
||||
|
||||
virtual ~TypeBridge() {};
|
||||
|
||||
TypeBridge(const google::protobuf::FieldDescriptor *desc);
|
||||
/* The field name in the SQL Table */
|
||||
virtual std::string name() { return desc->name(); }
|
||||
/* The expression in the create stmt for this type. */
|
||||
virtual std::string sql_create_stmt()
|
||||
{ return name() + " " + sql_type() + (desc->is_required() ? " NOT NULL": ""); };
|
||||
|
||||
/* The mapped type */
|
||||
virtual std::string sql_type() = 0;
|
||||
virtual int element_size() { return 0; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *) { };
|
||||
|
||||
/* A common function that handles NULL values for fields */
|
||||
bool insert_null(MYSQL_BIND *bind, const google::protobuf::Message *msg) {
|
||||
const google::protobuf::Reflection *ref = msg->GetReflection();
|
||||
if (!ref->HasField(*msg, desc)) {
|
||||
bind->buffer_type = MYSQL_TYPE_NULL;
|
||||
return true; // handled
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg) = 0;
|
||||
};
|
||||
|
||||
struct TypeBridge_repeated : TypeBridge {
|
||||
TypeBridge *inner;
|
||||
char *buffer;
|
||||
TypeBridge_repeated(const google::protobuf::FieldDescriptor *desc, TypeBridge *inner)
|
||||
: TypeBridge(desc), inner(inner), buffer(0) {};
|
||||
virtual std::string sql_type() { return "blob"; };
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_int32 : TypeBridge {
|
||||
int32_t buffer;
|
||||
TypeBridge_int32(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
virtual std::string sql_type() { return "INT"; };
|
||||
virtual int element_size() { return 4; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_uint32 : TypeBridge {
|
||||
uint32_t buffer;
|
||||
TypeBridge_uint32(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "INT"; };
|
||||
virtual int element_size() { return 4; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_int64 : TypeBridge {
|
||||
int64_t buffer;
|
||||
TypeBridge_int64(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
virtual std::string sql_type() { return "BIGINT"; };
|
||||
virtual int element_size() { return 8; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_uint64 : TypeBridge {
|
||||
uint64_t buffer;
|
||||
TypeBridge_uint64(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "BIGINT"; };
|
||||
virtual int element_size() { return 8; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
struct TypeBridge_double : TypeBridge {
|
||||
double buffer;
|
||||
TypeBridge_double(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "DOUBLE"; };
|
||||
virtual int element_size() { return 8; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
struct TypeBridge_float : TypeBridge {
|
||||
float buffer;
|
||||
TypeBridge_float(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "FLOAT"; };
|
||||
virtual int element_size() { return 4; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
struct TypeBridge_bool : TypeBridge {
|
||||
bool buffer;
|
||||
TypeBridge_bool(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "TINYINT"; };
|
||||
virtual int element_size() { return 1; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_string : TypeBridge {
|
||||
TypeBridge_string(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
virtual std::string sql_type() { return "TEXT"; };
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_enum : TypeBridge {
|
||||
int32_t size;
|
||||
TypeBridge_enum(const google::protobuf::FieldDescriptor *desc) : TypeBridge(desc) {};
|
||||
virtual std::string sql_type();
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
};
|
||||
|
||||
struct TypeBridge_message : TypeBridge {
|
||||
const google::protobuf::Descriptor *msg_type;
|
||||
int nesting_level;
|
||||
int field_count;
|
||||
std::vector<TypeBridge *> types;
|
||||
std::vector<int> *selector;
|
||||
|
||||
/* Pointer to the toplevel message */
|
||||
TypeBridge_message *parent;
|
||||
|
||||
TypeBridge_message * top_level_msg() {
|
||||
TypeBridge_message *p = this;
|
||||
while (p->parent != 0) p = p->parent;
|
||||
return p;
|
||||
}
|
||||
|
||||
std::vector<TypeBridge_message *> repeated_message_stack;
|
||||
|
||||
TypeBridge_message(const google::protobuf::FieldDescriptor *desc,
|
||||
const google::protobuf::Descriptor *msg_type,
|
||||
TypeBridge_message *parent)
|
||||
: TypeBridge(desc), msg_type(msg_type), parent(parent) {
|
||||
if (parent)
|
||||
nesting_level = parent->nesting_level+1;
|
||||
else
|
||||
nesting_level = 0;
|
||||
};
|
||||
virtual std::string sql_create_stmt();
|
||||
virtual std::string sql_type() { return ""; };
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
/* Returns the number of enclosed fields */
|
||||
int gatherTypes(StringJoiner &insert_stmt, StringJoiner &primary_key);
|
||||
};
|
||||
|
||||
TypeBridge_message top_level_msg;
|
||||
|
||||
std::string result_table_name;
|
||||
|
||||
int field_size_at_pos(const google::protobuf::Message *msg, std::vector<int> selector, int pos);
|
||||
|
||||
|
||||
public:
|
||||
DatabaseProtobufAdapter() : db(0), top_level_msg(0, 0, 0) {}
|
||||
void set_database_handle(Database *db) { this->db = db; }
|
||||
void create_table(const google::protobuf::Descriptor *);
|
||||
bool insert_row(const google::protobuf::Message *msg);
|
||||
std::string result_table() { return result_table_name; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user