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:
Christian Dietrich
2013-03-25 16:04:05 +01:00
parent 59e5fd3169
commit f18cddc63c
25 changed files with 1161 additions and 119 deletions

View 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