diff --git a/galera/src/galera_info.cpp b/galera/src/galera_info.cpp index d7bfe16eb..0513e0327 100644 --- a/galera/src/galera_info.cpp +++ b/galera/src/galera_info.cpp @@ -5,6 +5,8 @@ #include #include +#include + using namespace galera; static size_t @@ -15,57 +17,51 @@ view_info_size (int members) /* create view info out of configuration message */ wsrep_view_info_t* galera_view_info_create (const gcs_act_cchange& conf, + int const my_idx, wsrep_uuid_t& my_uuid) { wsrep_view_info_t* ret = static_cast( - ::malloc(view_info_size(conf.memb_num))); + ::malloc(view_info_size(conf.memb.size()))); if (ret) { - const char* str = conf.memb; - int m; - - wsrep_uuid_t uuid; - memcpy(uuid.data, conf.uuid.data, sizeof(uuid.data)); - wsrep_seqno_t seqno = conf.seqno != GCS_SEQNO_ILL ? - conf.seqno : WSREP_SEQNO_UNDEFINED; - wsrep_gtid_t gtid = { uuid, seqno }; + wsrep_uuid_t const uuid(to_wsrep_uuid(conf.uuid)); + wsrep_seqno_t const seqno + (conf.seqno != GCS_SEQNO_ILL ? conf.seqno : WSREP_SEQNO_UNDEFINED); + wsrep_gtid_t const gtid = { uuid, seqno }; ret->state_id = gtid; ret->view = conf.conf_id; ret->status = conf.conf_id != -1 ? WSREP_VIEW_PRIMARY : WSREP_VIEW_NON_PRIMARY; ret->my_idx = -1; - ret->memb_num = conf.memb_num; + ret->memb_num = conf.memb.size(); ret->proto_ver = conf.appl_proto_ver; - for (m = 0; m < ret->memb_num; m++) { - wsrep_member_info_t* member = &ret->members[m]; + for (int m = 0; m < ret->memb_num; ++m) + { + const gcs_act_cchange::member& cm(conf.memb[m]); // from + wsrep_member_info_t& wm(ret->members[m]); // to - size_t id_len = strlen(str); - gu_uuid_scan (str, id_len,reinterpret_cast(&member->id)); - str = str + id_len + 1; + wm.id = to_wsrep_uuid(cm.uuid_); - if (member->id == my_uuid) + if (wm.id == my_uuid) { ret->my_idx = m; } - strncpy(member->name, str, sizeof(member->name) - 1); - member->name[sizeof(member->name) - 1] = '\0'; - str = str + strlen(str) + 1; + strncpy(wm.name, cm.name_.c_str(), sizeof(wm.name) - 1); + wm.name[sizeof(wm.name) - 1] = '\0'; - strncpy(member->incoming, str, sizeof(member->incoming) - 1); - member->incoming[sizeof(member->incoming) - 1] = '\0'; - str = str + strlen(str) + 1; + strncpy(wm.incoming, cm.incoming_.c_str(), sizeof(wm.incoming) - 1); + wm.incoming[sizeof(wm.incoming) - 1] = '\0'; - str += sizeof(gcs_seqno_t); // skip cached seqno. } - if (WSREP_UUID_UNDEFINED == my_uuid && conf.my_idx >= 0) + if (WSREP_UUID_UNDEFINED == my_uuid && my_idx >= 0) { assert(-1 == ret->my_idx); - ret->my_idx = conf.my_idx; + ret->my_idx = my_idx; assert(ret->my_idx < ret->memb_num); my_uuid = ret->members[ret->my_idx].id; } diff --git a/galera/src/galera_info.hpp b/galera/src/galera_info.hpp index 685eadae5..14a03e0c2 100644 --- a/galera/src/galera_info.hpp +++ b/galera/src/galera_info.hpp @@ -7,10 +7,11 @@ #include "wsrep_api.h" /* create view info out of configuration message - * if my_uuid is defined - use it to determine my_idx, - * otherwise set my_uuid according to conf.my_idx */ + * if my_uuid is defined - use it to determine wsrep_view_info_t::my_idx, + * otherwise set my_uuid according to my_idx */ extern wsrep_view_info_t* galera_view_info_create (const gcs_act_cchange& conf, + int my_idx, wsrep_uuid_t& my_uuid); /* make a copy of view info object */ diff --git a/galera/src/gcs_dummy.cpp b/galera/src/gcs_dummy.cpp index a094df56e..f892e90be 100644 --- a/galera/src/gcs_dummy.cpp +++ b/galera/src/gcs_dummy.cpp @@ -1,8 +1,9 @@ // -// Copyright (C) 2011-2012 Codership Oy +// Copyright (C) 2011-2015 Codership Oy // #include "galera_gcs.hpp" +#include "uuid.hpp" namespace galera { @@ -74,31 +75,33 @@ namespace galera { gcs_act_cchange cc; + gcs_node_state_t const my_state + (primary ? GCS_NODE_STATE_JOINED : GCS_NODE_STATE_NON_PRIM); + if (primary) { ++global_seqno_; - cc.seqno = global_seqno_; + + cc.seqno = global_seqno_; cc.conf_id = 1; - memcpy (cc.uuid.data, &uuid_, sizeof(uuid_)); - cc.memb_num = 1; - cc.my_idx = 0; - cc.my_state = GCS_NODE_STATE_JOINED; + cc.uuid = uuid_; cc.repl_proto_ver = repl_proto_ver_; cc.appl_proto_ver = appl_proto_ver_; - char* const str(cc.memb); - ssize_t offt(0); - offt += gu_uuid_print (&uuid_, str, GU_UUID_STR_LEN+1) + 1; - offt += sprintf (str + offt, "%s", my_name_.c_str()) + 1; - sprintf (str + offt, "%s", incoming_.c_str()); + /* we have single member here */ + gcs_act_cchange::member m; + + m.uuid_ = uuid_; + m.name_ = my_name_; + m.incoming_ = incoming_; + m.state_ = my_state; + + cc.memb.push_back(m); } else { cc.seqno = GCS_SEQNO_ILL; cc.conf_id = -1; - cc.memb_num = 0; - cc.my_idx = -1; - cc.my_state = GCS_NODE_STATE_NON_PRIM; } cc_size_ = cc.write(&cc_); @@ -109,7 +112,6 @@ namespace galera return -ENOMEM; } - return cc_size_; } @@ -124,7 +126,6 @@ namespace galera if (ret > 0) { - // state_ = S_CONNECTED; cond_.signal(); ret = 0; } @@ -204,14 +205,18 @@ namespace galera gcs_act_cchange const cc(act.buf, act.size); - if (cc.my_idx < 0) + act.seqno_g = (cc.conf_id >= 0 ? 0 : -1); + + int const my_idx(act.seqno_g); + + if (my_idx < 0) { - assert (0 == cc.memb_num); + assert (0 == cc.memb.size()); state_ = S_CLOSED; } else { - assert (1 == cc.memb_num); + assert (1 == cc.memb.size()); state_ = S_CONNECTED; } diff --git a/galera/src/ist_proto.hpp b/galera/src/ist_proto.hpp index aca10f162..bd8f9c452 100644 --- a/galera/src/ist_proto.hpp +++ b/galera/src/ist_proto.hpp @@ -555,22 +555,23 @@ namespace galera case Message::T_CCHANGE: case Message::T_SKIP: { - size_t offset(0); + size_t offset(0); int64_t seqno_g(msg.seqno()); // compatibility with 3.x if (gu_unlikely(version_ < 8)) // compatibility with 3.x { assert(msg.type() == Message::T_TRX); - int64_t seqno_g, seqno_d; + int64_t seqno_d; buf.resize(sizeof(seqno_g) + sizeof(seqno_d)); n = asio::read(socket, asio::buffer(&buf[0],buf.size())); if (n != buf.size()) { - gu_throw_error(EPROTO) << - "error reading trx meta data"; + assert(0); + gu_throw_error(EPROTO) + << "error reading trx meta data"; } offset = gu::unserialize8(&buf[0],buf.size(),0,seqno_g); @@ -597,10 +598,10 @@ namespace galera msg.set_type_seqno(type, seqno_g); } - else + else // end compatibility with 3.x { assert(seqno_g > 0); - } // end compatibility with 3.x + } assert(msg.seqno() > 0); @@ -631,7 +632,7 @@ namespace galera * but it should not change below. Saving const for later * assert(). */ Message::Type const msg_type(msg.type()); - gcs_act_type const gcs_type + gcs_act_type const gcs_type (msg_type == Message::T_CCHANGE ? GCS_ACT_CCHANGE : GCS_ACT_WRITESET); diff --git a/galera/src/replicator_smm.cpp b/galera/src/replicator_smm.cpp index 1ea3ac09f..b64f3a771 100644 --- a/galera/src/replicator_smm.cpp +++ b/galera/src/replicator_smm.cpp @@ -397,7 +397,7 @@ wsrep_status_t galera::ReplicatorSMM::async_recv(void* recv_ctx) gcs_act_cchange const cc; wsrep_uuid_t tmp(uuid_); wsrep_view_info_t* const err_view - (galera_view_info_create(cc, tmp)); + (galera_view_info_create(cc, -1, tmp)); view_cb_(app_ctx_, recv_ctx, err_view, 0, 0); free(err_view); } @@ -1492,13 +1492,14 @@ galera::ReplicatorSMM::update_incoming_list(const wsrep_view_info_t& view) } } -static galera::Replicator::State state2repl(const gcs_act_cchange& conf) +static galera::Replicator::State state2repl(gcs_node_state const my_state, + int const my_idx) { - switch (conf.my_state) + switch (my_state) { case GCS_NODE_STATE_NON_PRIM: - if (conf.my_idx >= 0) return galera::Replicator::S_CONNECTED; - else return galera::Replicator::S_CLOSING; + if (my_idx >= 0) return galera::Replicator::S_CONNECTED; + else return galera::Replicator::S_CLOSING; case GCS_NODE_STATE_PRIM: return galera::Replicator::S_CONNECTED; case GCS_NODE_STATE_JOINER: @@ -1509,10 +1510,11 @@ static galera::Replicator::State state2repl(const gcs_act_cchange& conf) return galera::Replicator::S_SYNCED; case GCS_NODE_STATE_DONOR: return galera::Replicator::S_DONOR; - case GCS_NODE_STATE_MAX:; + case GCS_NODE_STATE_MAX: + assert(0); } - gu_throw_fatal << "unhandled gcs state: " << conf.my_state; + gu_throw_fatal << "unhandled gcs state: " << my_state; GU_DEBUG_NORETURN; } @@ -1524,8 +1526,6 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, gcs_act_cchange const conf(cc.buf, cc.size); - assert(cc.seqno_g == conf.seqno); - bool const from_IST(0 == cc.seqno_l); LocalOrder lo(cc.seqno_l); @@ -1545,12 +1545,22 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, assert(!from_IST || conf.repl_proto_ver >= 8); } + // we must have either my_idx or uuid_ defined + assert(cc.seqno_g >= 0 || uuid_ != WSREP_UUID_UNDEFINED); + wsrep_uuid_t new_uuid(uuid_); - wsrep_view_info_t* const view_info(galera_view_info_create(conf, new_uuid)); + wsrep_view_info_t* const view_info + (galera_view_info_create(conf, (!from_IST ? cc.seqno_g : -1), new_uuid)); + int const my_idx(view_info->my_idx); + gcs_node_state_t const my_state + (my_idx >= 0 ? conf.memb[my_idx].state_ : GCS_NODE_STATE_NON_PRIM); + + assert(my_state >= GCS_NODE_STATE_NON_PRIM); + assert(my_state < GCS_NODE_STATE_MAX); wsrep_seqno_t const group_seqno(view_info->state_id.seqno); const wsrep_uuid_t& group_uuid (view_info->state_id.uuid); - assert(group_seqno == cc.seqno_g); + assert(group_seqno == conf.seqno); if (!from_IST) { @@ -1570,10 +1580,10 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, log_info << "####### My UUID: " << uuid_; - if (cc.seqno_g != WSREP_SEQNO_UNDEFINED && - cc.seqno_g <= sst_seqno_) + if (conf.seqno != WSREP_SEQNO_UNDEFINED && + conf.seqno <= sst_seqno_) { - log_info << "####### skipping CC " << cc.seqno_g + log_info << "####### skipping CC " << conf.seqno << (from_IST ? ", from IST" : ", local"); // applied already in SST/IST, skip @@ -1593,12 +1603,11 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, update_incoming_list(*view_info); - log_info << "####### processing CC " << cc.seqno_g + log_info << "####### processing CC " << conf.seqno << (from_IST ? ", from IST" : ", local"); bool const st_required - (state_transfer_required(*view_info, - conf.my_state == GCS_NODE_STATE_PRIM)); + (state_transfer_required(*view_info, my_state == GCS_NODE_STATE_PRIM)); void* app_req(0); size_t app_req_len(0); @@ -1651,7 +1660,7 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, } } - Replicator::State const next_state(state2repl(conf)); + Replicator::State const next_state(state2repl(my_state, my_idx)); if (conf.conf_id >= 0) // Primary configuration { @@ -1712,8 +1721,7 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, else if (conf.seqno > cert_.position()) { assert(!app_waits_sst); - assert(group_uuid == conf.uuid); - assert(group_seqno == cc.seqno_g); + assert(group_uuid == conf.uuid); assert(group_seqno == conf.seqno); /* since CC does not pass certification, need to adjust cert @@ -1835,7 +1843,7 @@ galera::ReplicatorSMM::process_conf_change(void* recv_ctx, free(view_info); - if (conf.conf_id < 0 && conf.memb_num == 0) { + if (conf.conf_id < 0 && conf.memb.size() == 0) { assert(cc.seqno_l > 0); assert(S_CLOSING == next_state); log_debug << "Received SELF-LEAVE. Closing connection."; diff --git a/galera/src/uuid.hpp b/galera/src/uuid.hpp index 906c546bb..dbd4c5e02 100644 --- a/galera/src/uuid.hpp +++ b/galera/src/uuid.hpp @@ -22,6 +22,16 @@ namespace galera return *reinterpret_cast(&uuid); } + inline const wsrep_uuid_t& to_wsrep_uuid(const gu_uuid_t& uuid) + { + return *reinterpret_cast(&uuid); + } + + inline wsrep_uuid_t& to_wsrep_uuid(gu_uuid_t& uuid) + { + return *reinterpret_cast(&uuid); + } + inline bool operator==(const wsrep_uuid_t& a, const wsrep_uuid_t& b) { return to_gu_uuid(a) == to_gu_uuid(b); diff --git a/galera/tests/ist_check.cpp b/galera/tests/ist_check.cpp index f3fa7253e..e832a2805 100644 --- a/galera/tests/ist_check.cpp +++ b/galera/tests/ist_check.cpp @@ -372,10 +372,6 @@ static void store_cc(gcache::GCache* const gcache, cc.seqno = i; cc.conf_id = conf_id++; - cc.memb = NULL; - cc.memb_size = 0; - cc.memb_num = 1; - cc.my_idx = 0; void* tmp; int const cc_size(cc.write(&tmp)); diff --git a/galerautils/src/gu_uuid.hpp b/galerautils/src/gu_uuid.hpp index 8d2d80ece..c6150a29b 100644 --- a/galerautils/src/gu_uuid.hpp +++ b/galerautils/src/gu_uuid.hpp @@ -113,7 +113,12 @@ class gu::UUID return sizeof(gu_uuid_t); } - const gu_uuid_t* uuid_ptr() const + const gu_uuid_t* ptr() const + { + return &uuid_; + } + + gu_uuid_t* ptr() { return &uuid_; } @@ -157,6 +162,12 @@ class gu::UUID return is; } + UUID& operator=(const gu_uuid_t& other) + { + uuid_ = other; + return *this; + } + protected: gu_uuid_t uuid_; }; // class UUID diff --git a/garb/garb_recv_loop.cpp b/garb/garb_recv_loop.cpp index 07c5ad651..ab91349fd 100644 --- a/garb/garb_recv_loop.cpp +++ b/garb/garb_recv_loop.cpp @@ -78,13 +78,18 @@ RecvLoop::loop() if (cc.conf_id > 0) /* PC */ { - if (GCS_NODE_STATE_PRIM == cc.my_state) + int const my_idx(act.seqno_g); + assert(my_idx >= 0); + + gcs_node_state const my_state(cc.memb[my_idx].state_); + + if (GCS_NODE_STATE_PRIM == my_state) { gcs_.request_state_transfer (config_.sst(),config_.donor()); gcs_.join(cc.seqno); } } - else if (cc.memb_num == 0) // SELF-LEAVE after closing connection + else if (cc.memb.size() == 0) // SELF-LEAVE after closing connection { log_info << "Exiting main loop"; return; diff --git a/gcs/src/gcs.cpp b/gcs/src/gcs.cpp index 675362d93..1a60b89fe 100644 --- a/gcs/src/gcs.cpp +++ b/gcs/src/gcs.cpp @@ -816,13 +816,16 @@ _join (gcs_conn_t* conn, gcs_seqno_t seqno) // TODO: this function does not provide any way for recv_thread to gracefully // exit in case of self-leave message. static void -gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) +gcs_handle_act_conf (gcs_conn_t* conn, gcs_act_rcvd* rcvd) { + const gcs_act& act(rcvd->act); gcs_act_cchange const conf(act.buf, act.buf_len); - long ret; + assert(rcvd->id >= 0 || 0 == conf.memb.size()); + + conn->my_idx = rcvd->id; - conn->my_idx = conf.my_idx; + long ret; gu_fifo_lock(conn->recv_q); { @@ -831,7 +834,7 @@ gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) conn->stop_sent = 0; conn->stop_count = 0; conn->conf_id = conf.conf_id; - conn->memb_num = conf.memb_num; + conn->memb_num = conf.memb.size(); _set_fc_limits (conn); @@ -850,14 +853,14 @@ gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) gu_fifo_release (conn->recv_q); if (conf.conf_id < 0) { - if (0 == conf.memb_num) { - assert (conf.my_idx < 0); + if (0 == conn->memb_num) { + assert (conn->my_idx < 0); gu_info ("Received SELF-LEAVE. Closing connection."); gcs_shift_state (conn, GCS_CONN_CLOSED); } else { gu_info ("Received NON-PRIMARY."); - assert (GCS_NODE_STATE_NON_PRIM == conf.my_state); + assert (GCS_NODE_STATE_NON_PRIM == conf.memb[conn->my_idx].state_); gcs_become_open (conn); conn->global_seqno = conf.seqno; } @@ -868,19 +871,21 @@ gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) assert (conf.conf_id >= 0); /* */ - if (conf.memb_num < 1) { + if (conn->memb_num < 1) { + assert(0); gu_fatal ("Internal error: PRIMARY configuration with %d nodes", - conf.memb_num); + conn->memb_num); abort(); } - if (conf.my_idx < 0 || conf.my_idx >= conf.memb_num) { + if (conn->my_idx < 0 || conn->my_idx >= conn->memb_num) { + assert(0); gu_fatal ("Internal error: index of this node (%d) is out of bounds: " - "[%d, %d]", conf.my_idx, 0, conf.memb_num - 1); + "[%d, %d]", conn->my_idx, 0, conn->memb_num - 1); abort(); } - if (conf.my_state < GCS_NODE_STATE_PRIM) { + if (conf.memb[conn->my_idx].state_ < GCS_NODE_STATE_PRIM) { gu_fatal ("Internal error: NON-PRIM node state in PRIM configuraiton"); abort(); } @@ -893,7 +898,9 @@ gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) // Ticket #600: commented out as unsafe under load _reset_pkt_size(conn); const gcs_conn_state_t old_state = conn->state; - switch (conf.my_state) { + + switch (conf.memb[conn->my_idx].state_) + { case GCS_NODE_STATE_PRIM: gcs_become_primary(conn); return; /* Below are not real state transitions, rather state recovery, * so bypassing state transition matrix */ @@ -903,7 +910,7 @@ gcs_handle_act_conf (gcs_conn_t* conn, const gcs_act& act) case GCS_NODE_STATE_SYNCED: conn->state = GCS_CONN_SYNCED; break; default: gu_fatal ("Internal error: unrecognized node state: %d", - conf.my_state); + conf.memb[conn->my_idx].state_); abort(); } @@ -1004,7 +1011,7 @@ gcs_handle_actions (gcs_conn_t* conn, gcs_handle_flow_control (conn, (const gcs_fc_event*)rcvd->act.buf); break; case GCS_ACT_CCHANGE: - gcs_handle_act_conf (conn, rcvd->act); + gcs_handle_act_conf (conn, rcvd); ret = 1; break; case GCS_ACT_STATE_REQ: diff --git a/gcs/src/gcs.hpp b/gcs/src/gcs.hpp index 04fc7ef3b..cb93edd1f 100644 --- a/gcs/src/gcs.hpp +++ b/gcs/src/gcs.hpp @@ -20,10 +20,13 @@ #include "gu_buf.h" #include "gcache.h" #include "gu_errno.h" -#include "gu_uuid.h" +#include "gu_uuid.hpp" #include "gu_status.hpp" +#include +#include + /*! @typedef @brief Sequence number type. */ typedef int64_t gcs_seqno_t; @@ -404,31 +407,32 @@ gcs_node_state_t; extern const char* gcs_node_state_to_str (gcs_node_state_t state); -/*! New configuration action */ +/*! New configuration action deserialized */ struct gcs_act_cchange { gcs_act_cchange(); gcs_act_cchange(const void* buf, int size); - ~gcs_act_cchange(); - int write(void** buf) const; // buf allocated by malloc(). + int write(void** buf) const; bool operator==(const gcs_act_cchange& other) const; + struct member + { + member() : uuid_(), name_(), incoming_(), cached_(), state_() {} + bool operator==(const member& other) const; + gu_uuid_t uuid_; + std::string name_; + std::string incoming_; + gcs_seqno_t cached_; + gcs_node_state state_; + }; + + std::vector memb; gu_uuid_t uuid; //! group UUID gcs_seqno_t seqno; //! last global seqno applied by this group gcs_seqno_t conf_id; //! configuration ID (-1 if non-primary) - char* memb; /*! member array (null-terminated ID, name, - * incoming address, 8-byte cached seqno) */ - int memb_size;//! size of member array (bytes) - int memb_num; //! number of members in configuration - int my_idx; //! index of this node in the configuration int repl_proto_ver; //! replicator protocol version to use int appl_proto_ver; //! application protocol version to use - gcs_node_state_t my_state; //! current node state - -private: - gcs_act_cchange(const gcs_act_cchange&); - gcs_act_cchange& operator=(const gcs_act_cchange&); }; std::ostream& diff --git a/gcs/src/gcs_act_cchange.cpp b/gcs/src/gcs_act_cchange.cpp index 46d8a8a2f..e917d5738 100644 --- a/gcs/src/gcs_act_cchange.cpp +++ b/gcs/src/gcs_act_cchange.cpp @@ -13,16 +13,12 @@ gcs_act_cchange::gcs_act_cchange() : + memb(), uuid(GU_UUID_NIL), seqno(GCS_SEQNO_ILL), conf_id(-1), - memb(NULL), - memb_size(0), - memb_num(0), - my_idx(-1), repl_proto_ver(-1), - appl_proto_ver(-1), - my_state(GCS_NODE_STATE_NON_PRIM) + appl_proto_ver(-1) {} static int @@ -59,16 +55,12 @@ inline std::istream& operator>>(std::istream& is, gcs_node_state_t& ns) gcs_act_cchange::gcs_act_cchange(const void* const cc_buf, int const cc_size) : + memb(), uuid(), seqno(), conf_id(), - memb(NULL), - memb_size(0), - memb_num(), - my_idx(), repl_proto_ver(), - appl_proto_ver(), - my_state() + appl_proto_ver() { const char* b(static_cast(cc_buf)); int const cc_ver(b[0]); @@ -93,27 +85,77 @@ gcs_act_cchange::gcs_act_cchange(const void* const cc_buf, int const cc_size) char c; int msg_ver; + int memb_num; is >> msg_ver >> c >> repl_proto_ver >> c >> appl_proto_ver >> c >> uuid >> c >> seqno >> c >> conf_id >> c - >> memb_num >> c - >> my_idx >> c - >> my_state; + >> memb_num; assert(cc_ver == msg_ver); b += str_len + 1; // memb array offset - memb_size = check_len - 1 - str_len - 1; - memb = static_cast(::operator new(memb_size)); - std::copy(b, b + memb_size, memb); + memb.reserve(memb_num); + + for (int i(0); i < memb_num; ++i) + { + gcs_act_cchange::member m; + + size_t id_len(::strlen(b)); + gu_uuid_scan(b, id_len, &m.uuid_); + b += id_len + 1; + + m.name_ = b; + b += m.name_.length() + 1; + + m.incoming_ = b; + b += m.incoming_.length() + 1; + + const gcs_seqno_t* cached(reinterpret_cast(b)); + m.cached_ = gu::gtoh(*cached); + b += sizeof(gcs_seqno_t); + + if (b[0] >= GCS_NODE_STATE_NON_PRIM && b[0] < GCS_NODE_STATE_MAX) + { + m.state_ = gcs_node_state(b[0]); + ++b; + } + else + { + assert(0); + gu_throw_error(EINVAL) << "Unrecognized node state in CC: " << b[0]; + } + + memb.push_back(m); + } + + assert(b - static_cast(cc_buf) == check_len); } -gcs_act_cchange::~gcs_act_cchange() +static size_t +_memb_size(const std::vector& m) { - delete[] memb; + size_t ret(0); + + for (size_t i(0); i < m.size(); ++i) + { + ret += GU_UUID_STR_LEN + 1; + ret += m[i].name_.length() + 1; + ret += m[i].incoming_.length() + 1; + ret += sizeof(gcs_seqno_t); // lowest cached + ret += sizeof(char); // state + } + + return ret; +} + +static size_t +_strcopy(const std::string& str, char* ptr) +{ + std::copy(str.begin(), str.end(), ptr); + return str.length(); } int @@ -127,41 +169,74 @@ gcs_act_cchange::write(void** buf) const << appl_proto_ver << ',' << uuid << ':' << seqno << ',' << conf_id << ',' - << memb_num << ',' - << my_idx << ',' - << my_state; + << memb.size(); std::string const str(os.str()); - int const payload_len(str.length() + 1 + memb_size); - int const check_off(1 + payload_len); // version byte + payload - int const sum_len(_checksum_len(cc_ver)); // checksum hash - int const ret(check_off + sum_len); // total message length + int const payload_len(str.length() + 1 + _memb_size(memb)); + int const check_offset(1 + payload_len); // version byte + payload + int const check_len(_checksum_len(cc_ver)); // checksum hash + int const ret(check_offset + check_len); // total message length /* using malloc() for C compatibility */ *buf = ::malloc(ret); if (NULL == *buf) { - gu_throw_error(ENOMEM) << "Failed to allocate " << memb_size + gu_throw_error(ENOMEM) << "Failed to allocate " << ret << " bytes for configuration change event."; } - gu::byte_t* b(static_cast(*buf)); + char* b(static_cast(*buf)); - assert(cc_ver < std::numeric_limits::max()); - b[0] = cc_ver; - std::copy(str.begin(), str.end(), b + 1); - b[1 + str.length()] = '\0'; - std::copy(memb, memb + memb_size, b + str.length() + 2); + assert(cc_ver < std::numeric_limits::max()); + + b[0] = cc_ver; ++b; + + b += _strcopy(str, b); + b[0] = '\0'; ++b; + + for (size_t i(0); i < memb.size(); ++i) + { + const gcs_act_cchange::member& m(memb[i]); + + b += gu_uuid_print(&m.uuid_, b, GU_UUID_STR_LEN+1); + b[0] = '\0'; ++b; + b += _strcopy(m.name_, b); + b[0] = '\0'; ++b; + b += _strcopy(m.incoming_, b); + b[0] = '\0'; ++b; + + gcs_seqno_t* const cached(reinterpret_cast(b)); + *cached = gu::htog(m.cached_); + b += sizeof(gcs_seqno_t); + + b[0] = m.state_; ++b; + } + + assert(static_cast(*buf) + check_offset == b); gu::byte_t check[16]; - gu::FastHash::digest(b, check_off, check); + gu::FastHash::digest(*buf, check_offset, check); + + std::copy(check, check + check_len, b); b += check_len; - std::copy(check, check + sum_len, b + check_off); + assert(static_cast(*buf) + ret == b); return ret; } +bool +gcs_act_cchange::member::operator==(const gcs_act_cchange::member& other) const +{ + return ( + uuid_ == other.uuid_ && + name_ == other.name_ && + incoming_ == other.incoming_ && + cached_ == other.cached_ && + state_ == other.state_ + ); +} + bool gcs_act_cchange::operator==(const gcs_act_cchange& other) const { @@ -171,10 +246,7 @@ gcs_act_cchange::operator==(const gcs_act_cchange& other) const uuid == other.uuid && seqno == other.seqno && conf_id == other.conf_id && - memb_num == other.memb_num && - my_idx == other.my_idx && - my_state == other.my_state && - memb_size == other.memb_size && - std::equal(memb, memb + memb_size, other.memb) + memb == other.memb ); } + diff --git a/gcs/src/gcs_group.cpp b/gcs/src/gcs_group.cpp index 166032aaa..ea43ed8ed 100644 --- a/gcs/src/gcs_group.cpp +++ b/gcs/src/gcs_group.cpp @@ -9,6 +9,7 @@ #include "gcs_priv.hpp" #include +#include #include @@ -1380,22 +1381,6 @@ gcs_group_handle_state_request (gcs_group_t* group, return act->act.buf_len; } -static ssize_t -group_memb_record_size (gcs_group_t* group) -{ - ssize_t ret = 0; - long idx; - - for (idx = 0; idx < group->num; idx++) { - ret += strlen(group->nodes[idx].id) + 1; - ret += strlen(group->nodes[idx].name) + 1; - ret += strlen(group->nodes[idx].inc_addr) + 1; - ret += sizeof(gcs_seqno_t); // cached seqno - } - - return ret; -} - /* Creates new configuration action */ ssize_t gcs_group_act_conf (gcs_group_t* group, @@ -1417,9 +1402,6 @@ gcs_group_act_conf (gcs_group_t* group, struct gcs_act_cchange conf; - conf.memb_size = group_memb_record_size(group); - conf.memb = static_cast(::operator new(conf.memb_size)); - if (GCS_GROUP_PRIMARY == group->state) { conf.seqno = ++group->act_id_; } else { @@ -1428,37 +1410,32 @@ gcs_group_act_conf (gcs_group_t* group, } conf.conf_id = group->conf_id; - conf.memb_num = group->num; - conf.my_idx = group->my_idx; conf.repl_proto_ver = group->quorum.repl_proto_ver; conf.appl_proto_ver = group->quorum.appl_proto_ver; memcpy (conf.uuid.data, &group->group_uuid, sizeof (gu_uuid_t)); if (group->num) { - assert (conf.my_idx >= 0); + assert (group->my_idx >= 0); - conf.my_state = group->nodes[group->my_idx].status; - - char* ptr(conf.memb); for (int idx = 0; idx < group->num; ++idx) { - strcpy (ptr, group->nodes[idx].id); - ptr += strlen(ptr) + 1; - strcpy (ptr, group->nodes[idx].name); - ptr += strlen(ptr) + 1; - strcpy (ptr, group->nodes[idx].inc_addr); - ptr += strlen(ptr) + 1; - gcs_seqno_t cached = gcs_node_cached(&group->nodes[idx]); - memcpy(ptr, &cached, sizeof(cached)); - ptr += sizeof(cached); + gcs_act_cchange::member m; + + gu_uuid_scan(group->nodes[idx].id, strlen(group->nodes[idx].id), + &m.uuid_); + m.name_ = group->nodes[idx].name; + m.incoming_ = group->nodes[idx].inc_addr; + m.cached_ = gcs_node_cached(&group->nodes[idx]); + m.state_ = group->nodes[idx].status; + + conf.memb.push_back(m); } } else { // self leave message assert (conf.conf_id < 0); - assert (conf.my_idx < 0); - conf.my_state = GCS_NODE_STATE_NON_PRIM; + assert (-1 == group->my_idx); } void* tmp; @@ -1469,7 +1446,7 @@ gcs_group_act_conf (gcs_group_t* group, if (rcvd->act.buf) { memcpy(const_cast(rcvd->act.buf), tmp, rcvd->act.buf_len); - rcvd->id = conf.seqno; + rcvd->id = group->my_idx; // passing own index in seqno_g } else { @@ -1478,7 +1455,7 @@ gcs_group_act_conf (gcs_group_t* group, } free(tmp); #else - rcvd->id = conf.seqno; + rcvd->id = group->my_idx; #endif /* GCS_FOR_GARB */ rcvd->act.type = GCS_ACT_CCHANGE; diff --git a/gcs/src/gcs_test.cpp b/gcs/src/gcs_test.cpp index 9f3f067fd..78d21455f 100644 --- a/gcs/src/gcs_test.cpp +++ b/gcs/src/gcs_test.cpp @@ -434,13 +434,15 @@ gcs_test_handle_configuration (gcs_conn_t* gcs, gcs_test_thread_t* thread) long ret; static gcs_seqno_t conf_id = 0; gcs_act_cchange const conf(thread->act.buf, thread->act.size); + int const my_idx(thread->act.seqno_g); + gcs_node_state my_state(conf.memb[my_idx].state_); gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; fprintf (stdout, "Got GCS_ACT_CCHANGE: Conf: %lld, " - "seqno: %lld, members: %d, my idx: %d, local seqno: %lld\n", + "seqno: %lld, members: %zd, my idx: %d, local seqno: %lld\n", (long long)conf.conf_id, (long long)conf.seqno, - conf.memb_num, conf.my_idx, (long long)thread->act.seqno_l); + conf.memb.size(), my_idx, (long long)thread->act.seqno_l); fflush (stdout); // NOTE: what really needs to be checked is seqno and group_uuid, but here @@ -448,7 +450,7 @@ gcs_test_handle_configuration (gcs_conn_t* gcs, gcs_test_thread_t* thread) // so for simplicity, just check conf_id. while (-EAGAIN == (ret = gu_to_grab (to, thread->act.seqno_l))); if (0 == ret) { - if (conf.my_state == GCS_NODE_STATE_PRIM) { + if (my_state == GCS_NODE_STATE_PRIM) { gcs_seqno_t seqno, s; fprintf (stdout,"Gap in configurations: ours: %lld, group: %lld.\n", (long long)conf_id, (long long)conf.conf_id); diff --git a/gcs/src/unit_tests/gcs_act_cchange_test.cpp b/gcs/src/unit_tests/gcs_act_cchange_test.cpp index ef2a9149c..bd6f9c2ce 100644 --- a/gcs/src/unit_tests/gcs_act_cchange_test.cpp +++ b/gcs/src/unit_tests/gcs_act_cchange_test.cpp @@ -18,16 +18,12 @@ START_TEST (zero_cc) { gcs_act_cchange const cc; - fail_unless(cc.uuid == GU_UUID_NIL); + fail_unless(cc.uuid == GU_UUID_NIL); fail_if(cc.seqno != GCS_SEQNO_ILL); fail_if(cc.conf_id != -1); - fail_if(cc.memb != NULL); - fail_if(cc.memb_size != 0); - fail_if(cc.memb_num != 0); - fail_if(cc.my_idx != -1); + fail_if(cc.memb.size() != 0); fail_if(cc.repl_proto_ver != -1); fail_if(cc.appl_proto_ver != -1); - fail_if(cc.my_state != GCS_NODE_STATE_NON_PRIM); } END_TEST @@ -63,11 +59,8 @@ START_TEST (serialization) cc_src.seqno = 1234567890; cc_src.conf_id = 234; - cc_src.memb_num = 3; - cc_src.my_idx = 1; cc_src.repl_proto_ver = 4; cc_src.appl_proto_ver = 5; - cc_src.my_state = GCS_NODE_STATE_JOINER; // TODO - add memb array @@ -83,11 +76,9 @@ START_TEST (serialization) fail_if(cc_dst.seqno != cc_src.seqno); fail_if(cc_dst.conf_id != cc_src.conf_id); - fail_if(cc_dst.memb_num != cc_src.memb_num); - fail_if(cc_dst.my_idx != cc_src.my_idx); + fail_if(cc_dst.memb.size() != cc_src.memb.size()); fail_if(cc_dst.repl_proto_ver != cc_src.repl_proto_ver); fail_if(cc_dst.appl_proto_ver != cc_src.appl_proto_ver); - fail_if(cc_dst.my_state != cc_src.my_state); } } END_TEST diff --git a/gcs/src/unit_tests/gcs_backend_test.cpp b/gcs/src/unit_tests/gcs_backend_test.cpp index 5d7404e8d..b11ad3f9b 100644 --- a/gcs/src/unit_tests/gcs_backend_test.cpp +++ b/gcs/src/unit_tests/gcs_backend_test.cpp @@ -5,6 +5,7 @@ */ #include +#undef fail // STL needs that #include #include #include diff --git a/gcs/src/unit_tests/gcs_core_test.cpp b/gcs/src/unit_tests/gcs_core_test.cpp index 73661526c..b081ca8d0 100644 --- a/gcs/src/unit_tests/gcs_core_test.cpp +++ b/gcs/src/unit_tests/gcs_core_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2013 Codership Oy + * Copyright (C) 2008-2015 Codership Oy * * $Id$ */ @@ -177,9 +177,18 @@ static bool COMMON_RECV_CHECKS(action_t* act, FAIL_IF (GCS_ACT_WRITESET != act->type && GCS_ACT_CCHANGE != act->type, "GCS_ACT_WRITESET != act->type (%d), while act->seqno: %lld", act->type, (long long)act->seqno); - FAIL_IF ((*seqno + 1) != act->seqno, - "expected seqno %lld, got %lld", - (long long)(*seqno + 1), (long long)act->seqno); + if (GCS_ACT_CCHANGE != act->type) + { + FAIL_IF ((*seqno + 1) != act->seqno, + "expected seqno %lld, got %lld", + (long long)(*seqno + 1), (long long)act->seqno); + } + else + { + FAIL_IF (act->seqno < 0, "Negative seqno: %lld", + (long long)act->seqno); + } + *seqno = *seqno + 1; } @@ -280,7 +289,7 @@ static bool CORE_SEND_END(action_t* act, long ret) // check if configuration is the one that we expected static long core_test_check_conf (const void* const conf_msg, int const conf_size, - bool prim, long my_idx, long memb_num) + bool const prim, long const my_idx, size_t const memb_num) { long ret = 0; @@ -293,13 +302,8 @@ core_test_check_conf (const void* const conf_msg, int const conf_size, ret = -1; } - if (conf.my_idx != my_idx) { - gu_error ("Expected my_idx = %ld, got %ld", my_idx, conf.my_idx); - ret = -1; - } - - if (conf.my_idx != my_idx) { - gu_error ("Expected my_idx = %ld, got %ld", my_idx, conf.my_idx); + if (conf.memb.size() != memb_num) { + gu_error ("Expected memb_num = %zd, got %zd", memb_num,conf.memb.size()); ret = -1; } diff --git a/gcs/src/unit_tests/gcs_defrag_test.cpp b/gcs/src/unit_tests/gcs_defrag_test.cpp index 5c396af55..ea8e32b61 100644 --- a/gcs/src/unit_tests/gcs_defrag_test.cpp +++ b/gcs/src/unit_tests/gcs_defrag_test.cpp @@ -5,6 +5,7 @@ */ #include +#undef fail // needed by STL #include #include #include diff --git a/gcs/src/unit_tests/gcs_fifo_test.cpp b/gcs/src/unit_tests/gcs_fifo_test.cpp index 3bd863794..4c8aa3b30 100644 --- a/gcs/src/unit_tests/gcs_fifo_test.cpp +++ b/gcs/src/unit_tests/gcs_fifo_test.cpp @@ -3,6 +3,7 @@ // $Id$ #include +#undef fail // needed by STL #include "gcs_fifo_test.hpp" #include "../gcs_fifo_lite.hpp" @@ -39,7 +40,7 @@ START_TEST (gcs_fifo_lite_test) *item = i; gcs_fifo_lite_push_tail (fifo); } - fail_if (fifo->used != FIFO_LENGTH, "fifo->used is %zu, expected %zu", + fail_if (fifo->used != FIFO_LENGTH, "fifo->used is %zu, expected %zu", fifo->used, FIFO_LENGTH); // test remove diff --git a/gcs/src/unit_tests/gcs_group_test.cpp b/gcs/src/unit_tests/gcs_group_test.cpp index 820f0b5d7..30af6d4ac 100644 --- a/gcs/src/unit_tests/gcs_group_test.cpp +++ b/gcs/src/unit_tests/gcs_group_test.cpp @@ -5,6 +5,7 @@ */ #include +#undef fail // needed by STL #include #include #include diff --git a/gcs/src/unit_tests/gcs_memb_test.cpp b/gcs/src/unit_tests/gcs_memb_test.cpp index a29c427b2..e33fc596e 100644 --- a/gcs/src/unit_tests/gcs_memb_test.cpp +++ b/gcs/src/unit_tests/gcs_memb_test.cpp @@ -5,8 +5,7 @@ */ #include - -#undef fail +#undef fail // needed by STL #include "gcs_memb_test.hpp" @@ -448,9 +447,10 @@ START_TEST(gcs_memb_test_465) fail_if (ret != act->buf_len); fail_if (proto_ver != 0 /* current version */, "proto_ver = %d", proto_ver); const gcs_act_cchange conf(act->buf, act->buf_len); - fail_if (conf.my_idx != 1); + int const my_idx(rcvd.id); + fail_if (my_idx != 1); /* according to #465 this was GCS_NODE_STATE_PRIM */ - fail_if (conf.my_state != GCS_NODE_STATE_SYNCED); + fail_if (conf.memb[my_idx].state_ != GCS_NODE_STATE_SYNCED); deliver_join_sync_msg (&group, 0, GCS_MSG_SYNC); // donor synced fail_if (verify_node_state_across_group (&group, 0, GCS_NODE_STATE_SYNCED)); diff --git a/gcs/src/unit_tests/gcs_node_test.cpp b/gcs/src/unit_tests/gcs_node_test.cpp index e21f2726c..6125b1e0e 100644 --- a/gcs/src/unit_tests/gcs_node_test.cpp +++ b/gcs/src/unit_tests/gcs_node_test.cpp @@ -5,6 +5,7 @@ */ #include +#undef fail // needed by STL #include #include #include diff --git a/gcs/src/unit_tests/gcs_proto_test.cpp b/gcs/src/unit_tests/gcs_proto_test.cpp index 2fd4ea72f..42d75de5d 100644 --- a/gcs/src/unit_tests/gcs_proto_test.cpp +++ b/gcs/src/unit_tests/gcs_proto_test.cpp @@ -7,6 +7,7 @@ #include #include #include +#undef fail // needed by STL #include "../gcs_act_proto.hpp" diff --git a/gcs/src/unit_tests/gcs_state_msg_test.cpp b/gcs/src/unit_tests/gcs_state_msg_test.cpp index 7ed7bf854..af48b8c50 100644 --- a/gcs/src/unit_tests/gcs_state_msg_test.cpp +++ b/gcs/src/unit_tests/gcs_state_msg_test.cpp @@ -3,6 +3,7 @@ // $Id$ #include +#undef fail // needed by STL #include #include "gcs_state_msg_test.hpp" #define GCS_STATE_MSG_ACCESS