// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2023 IBM, Inc. * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. */ #ifndef MON_NVMEOFGWSERIALIZE_H_ #define MON_NVMEOFGWSERIALIZE_H_ #define dout_context g_ceph_context #define dout_subsys ceph_subsys_mon #undef dout_prefix #define MODULE_PREFFIX "nvmeofgw " #define dout_prefix *_dout << MODULE_PREFFIX << __PRETTY_FUNCTION__ << " " #define MAX_SUPPORTED_ANA_GROUPS 16 inline std::ostream& operator<<( std::ostream& os, const gw_exported_states_per_group_t value) { switch (value) { case gw_exported_states_per_group_t::GW_EXPORTED_OPTIMIZED_STATE: os << "OPTIMIZED "; break; case gw_exported_states_per_group_t::GW_EXPORTED_INACCESSIBLE_STATE: os << "INACCESSIBLE "; break; default: os << "Invalid " << (int)value << " "; } return os; } inline std::ostream& operator<<( std::ostream& os, const gw_states_per_group_t value) { switch (value) { case gw_states_per_group_t::GW_IDLE_STATE: os << "IDLE "; break; case gw_states_per_group_t::GW_STANDBY_STATE: os << "STANDBY "; break; case gw_states_per_group_t::GW_ACTIVE_STATE: os << "ACTIVE "; break; case gw_states_per_group_t::GW_OWNER_WAIT_FAILBACK_PREPARED: os << "OWNER_FAILBACK_PREPARED "; break; case gw_states_per_group_t::GW_WAIT_FAILBACK_PREPARED: os << "WAIT_FAILBACK_PREPARED "; break; case gw_states_per_group_t::GW_WAIT_BLOCKLIST_CMPL: os << "WAIT_BLOCKLIST_CMPL "; break; default: os << "Invalid " << (int)value << " "; } return os; } inline std::ostream& operator<<( std::ostream& os, const gw_availability_t value) { switch (value) { case gw_availability_t::GW_CREATED: os << "CREATED"; break; case gw_availability_t::GW_AVAILABLE: os << "AVAILABLE"; break; case gw_availability_t::GW_UNAVAILABLE: os << "UNAVAILABLE"; break; case gw_availability_t::GW_DELETING: os << "DELETING"; break; default: os << "Invalid " << (int)value << " "; } return os; } inline std::ostream& operator<<(std::ostream& os, const SmState value) { os << "SM_STATE [ "; for (auto& state_itr: value ) { os << value.at(state_itr.first); } os << "]"; return os; } inline std::ostream& operator<<(std::ostream& os, const BeaconNamespace value) { os << "BeaconNamespace( anagrpid:" << value.anagrpid << ", nonce:" << value.nonce <<" )"; return os; } inline std::ostream& operator<<(std::ostream& os, const BeaconListener value) { os << "BeaconListener( addrfam:" << value.address_family << ", addr:" << value.address << ", svcid:" << value.svcid << " )"; return os; } inline std::ostream& operator<<(std::ostream& os, const BeaconSubsystem value) { os << "BeaconSubsystem( nqn:" << value.nqn << ", listeners [ "; for (const auto& list: value.listeners) os << list << " "; os << "] namespaces [ "; for (const auto& ns: value.namespaces) os << ns << " "; os << "] )"; return os; } inline std::ostream& operator<<(std::ostream& os, const NqnState value) { os << "NqnState( nqn: " << value.nqn << ", " << value.ana_state << " )"; return os; } inline std::ostream& operator<<( std::ostream& os, const NvmeGwClientState value) { os << "NvmeGwState { group id: " << value.group_id << " gw_map_epoch " << value.gw_map_epoch << " availablilty "<< value.availability << " GwSubsystems: [ "; for (const auto& sub: value.subsystems) { os << sub.second << " "; } os << " ] }"; return os; }; inline std::ostream& operator<<(std::ostream& os, const NvmeGroupKey value) { os << "NvmeGroupKey {" << value.first << "," << value.second << "}"; return os; }; inline std::ostream& operator<<( std::ostream& os, const NvmeGwMonClientStates value) { os << "NvmeGwMap "; for (auto& gw_state: value) { os << "\n" << MODULE_PREFFIX <<" { == gw_id: " << gw_state.first << " -> " << gw_state.second << "}"; } os << "}"; return os; }; inline std::ostream& operator<<(std::ostream& os, const NvmeNonceVector value) { for (auto & nonces : value) { os << nonces << " "; } return os; } inline std::ostream& operator<<(std::ostream& os, const NvmeAnaNonceMap value) { if (value.size()) { os << "\n" << MODULE_PREFFIX; } for (auto &nonce_map : value) { os << " ana_grp: " << nonce_map.first << " [ " << nonce_map.second << "]\n"<< MODULE_PREFFIX; } return os; } inline std::ostream& print_gw_created_t( std::ostream& os, const NvmeGwMonState value, size_t num_ana_groups) { os << "==Internal map ==NvmeGwCreated { ana_group_id " << value.ana_grp_id << " osd_epochs: "; for (auto& blklst_itr: value.blocklist_data) { os << " " << blklst_itr.first <<": " << blklst_itr.second.osd_epoch << ":" < { " << group_gws.second << " }"; } os << "]"; return os; } inline void encode(const ana_state_t& st, ceph::bufferlist &bl) { ENCODE_START(1, 1, bl); encode((uint32_t)st.size(), bl); for (const auto& gr: st) { encode((uint32_t)gr.first, bl); encode((uint32_t)gr.second, bl); } ENCODE_FINISH(bl); } inline void decode(ana_state_t& st, ceph::buffer::list::const_iterator &bl) { uint32_t n; DECODE_START(1, bl); decode(n, bl); st.resize(n); for (uint32_t i = 0; i < n; i++) { uint32_t a, b; decode(a, bl); decode(b, bl); st[i].first = (gw_exported_states_per_group_t)a; st[i].second = (epoch_t)b; } DECODE_FINISH(bl); } inline void encode( const GwSubsystems& subsystems, ceph::bufferlist &bl, uint64_t features) { uint8_t version = 1; if (HAVE_FEATURE(features, NVMEOFHA)) { version = 2; } ENCODE_START(version, version, bl); encode((uint32_t)subsystems.size(), bl); for (const auto& sub: subsystems) { encode(sub.second.nqn, bl); if (version == 1) { dout(20) << "encode ana_state vector version1 = " << version << dendl; /* Version 1 requires exactly 16 entries */ ana_state_t filled(sub.second.ana_state); filled.resize( MAX_SUPPORTED_ANA_GROUPS, std::make_pair( gw_exported_states_per_group_t::GW_EXPORTED_INACCESSIBLE_STATE, 0)); encode(filled, bl); } else { dout(20) << "encode ana_state vector version2 = " << version << dendl; encode(sub.second.ana_state, bl); } } ENCODE_FINISH(bl); } inline void decode( GwSubsystems& subsystems, ceph::bufferlist::const_iterator& bl) { uint32_t num_subsystems; DECODE_START(2, bl); decode(num_subsystems, bl); subsystems.clear(); for (uint32_t i=0; i= 2) { encode((uint32_t)state.data.size(), bl); for (auto &tm_itr:state.data) { encode((uint32_t)tm_itr.first, bl);// encode key uint32_t tick = tm_itr.second.timer_started; uint8_t val = tm_itr.second.timer_value; encode(tick, bl); encode(val, bl); auto endtime = tm_itr.second.end_time; // Convert the time point to milliseconds since the epoch uint64_t millisecondsSinceEpoch = std::chrono::duration_cast( endtime.time_since_epoch()).count(); encode(millisecondsSinceEpoch , bl); } } else { encode((uint32_t)MAX_SUPPORTED_ANA_GROUPS, bl); Tmdata empty; for (uint32_t i = 0; i < MAX_SUPPORTED_ANA_GROUPS; i++) { auto tmiter = state.data.find(i); const Tmdata *to_encode = ∅ if (tmiter != state.data.end()) { to_encode = &(tmiter->second); } encode(to_encode->timer_started, bl); encode(to_encode->timer_value, bl); auto endtime = to_encode->end_time; // Convert the time point to milliseconds since the epoch uint64_t millisecondsSinceEpoch = std::chrono::duration_cast( endtime.time_since_epoch()).count(); encode(millisecondsSinceEpoch , bl); } } ENCODE_FINISH(bl); } inline void decode( NvmeGwTimerState& state, ceph::bufferlist::const_iterator& bl) { DECODE_START(2, bl); dout(20) << "decode NvmeGwTimers version = " << struct_v << dendl; uint32_t size; decode(size, bl); for (uint32_t i = 0; i = 2) { decode(tm_key, bl); decode(tick, bl); decode(val, bl); Tmdata tm; tm.timer_started = tick; tm.timer_value = val; uint64_t milliseconds; decode(milliseconds, bl); auto duration = std::chrono::milliseconds(milliseconds); tm.end_time = std::chrono::time_point(duration); state.data[tm_key] = tm; } else { decode(tick, bl); decode(val, bl); Tmdata tm; tm.timer_started = tick; tm.timer_value = val; uint64_t milliseconds; decode(milliseconds, bl); if (tm.timer_started) { // relevant only entries with started timers in the state auto duration = std::chrono::milliseconds(milliseconds); tm.end_time = std::chrono::time_point(duration); state.data[i] = tm; } } } DECODE_FINISH(bl); } inline void encode(const NvmeAnaNonceMap& nonce_map, ceph::bufferlist &bl, uint64_t features) { ENCODE_START(1, 1, bl); encode((uint32_t)nonce_map.size(), bl); for (auto& ana_group_nonces : nonce_map) { // ana group id encode(ana_group_nonces.first, bl); // encode the vector size encode ((uint32_t)ana_group_nonces.second.size(), bl); for (auto& nonce: ana_group_nonces.second) encode(nonce, bl); } ENCODE_FINISH(bl); } inline void decode( NvmeAnaNonceMap& nonce_map, ceph::buffer::list::const_iterator &bl) { dout(20) << "decode nonce map " << dendl; uint32_t map_size; NvmeAnaGrpId ana_grp_id; uint32_t vector_size; std::string nonce; DECODE_START(1, bl); decode(map_size, bl); for (uint32_t i = 0; i= 2) { encode((uint32_t)gw.second.sm_state.size(), bl); for (auto &state_it:gw.second.sm_state) { encode((uint32_t)state_it.first, bl); //key of map encode((uint32_t)state_it.second, bl);//value of map } encode((uint32_t)gw.second.availability, bl); encode((uint16_t)gw.second.performed_full_startup, bl); encode((uint16_t)gw.second.last_gw_map_epoch_valid, bl); encode(gw.second.subsystems, bl); encode((uint32_t)gw.second.blocklist_data.size(), bl); for (auto &blklst_itr: gw.second.blocklist_data) { encode((uint32_t)blklst_itr.first, bl); encode((uint32_t)blklst_itr.second.osd_epoch, bl); encode((uint32_t)blklst_itr.second.is_failover, bl); } } else { gw_states_per_group_t states[MAX_SUPPORTED_ANA_GROUPS]; for (int i = 0; i < MAX_SUPPORTED_ANA_GROUPS; i++) states[i] = gw_states_per_group_t::GW_IDLE_STATE; for (auto &state_it:gw.second.sm_state) states[state_it.first] = state_it.second; for (int i = 0; i < MAX_SUPPORTED_ANA_GROUPS; i++) encode((uint32_t)states[i], bl); encode((uint32_t)gw.second.availability, bl); encode((uint16_t)gw.second.performed_full_startup, bl); encode((uint16_t)gw.second.last_gw_map_epoch_valid, bl); encode(gw.second.subsystems, bl); // TODO reuse but put features - encode version Blocklist_data bl_data[MAX_SUPPORTED_ANA_GROUPS]; for (auto &blklst_itr: gw.second.blocklist_data) { bl_data[blklst_itr.first].osd_epoch = blklst_itr.second.osd_epoch; bl_data[blklst_itr.first].is_failover = blklst_itr.second.is_failover; } for (int i = 0; i < MAX_SUPPORTED_ANA_GROUPS; i++) { encode((uint32_t)bl_data[i].osd_epoch, bl); encode((bool)bl_data[i].is_failover, bl); } } encode(gw.second.nonce_map, bl, features); } ENCODE_FINISH(bl); } inline void decode( NvmeGwMonStates& gws, ceph::buffer::list::const_iterator &bl) { gws.clear(); uint32_t num_created_gws; DECODE_START(2, bl); dout(20) << "decode NvmeGwMonStates. struct_v: " << struct_v << dendl; decode(num_created_gws, bl); dout(20) << "decode NvmeGwMonStates. num gws " << num_created_gws << dendl; std::set created_anagrps; for (uint32_t i = 0; i= 2) { decode(size, bl); for (uint32_t i = 0; i = 2) { decode(size, bl); for (uint32_t i=0; i& created_gws, ceph::bufferlist &bl, uint64_t features) { ENCODE_START(1, 1, bl); encode ((uint32_t)created_gws.size(), bl); // number of groups for (auto& group_gws: created_gws) { auto& group_key = group_gws.first; encode(group_key.first, bl); // pool encode(group_key.second, bl); // group auto& gws = group_gws.second; encode(gws, bl, features); // encode group gws } ENCODE_FINISH(bl); } inline void decode( std::map& created_gws, ceph::buffer::list::const_iterator &bl) { created_gws.clear(); uint32_t ngroups = 0; DECODE_START(1, bl); decode(ngroups, bl); for (uint32_t i = 0; i& gmap, ceph::bufferlist &bl, uint64_t features) { ENCODE_START(1, 1, bl); encode ((uint32_t)gmap.size(), bl); // number of groups for (auto& group_state: gmap) { auto& group_key = group_state.first; encode(group_key.first, bl); // pool encode(group_key.second, bl); // group encode(group_state.second, bl, features); } ENCODE_FINISH(bl); } // Start decode NvmeGroupKey, NvmeGwMap inline void decode( std::map& gmap, ceph::buffer::list::const_iterator &bl) { gmap.clear(); uint32_t ngroups; DECODE_START(1, bl); decode(ngroups, bl); for (uint32_t i = 0; i& gmetadata, ceph::bufferlist &bl, uint64_t features) { ENCODE_START(1, 1, bl); encode ((uint32_t)gmetadata.size(), bl); // number of groups for (auto& group_md: gmetadata) { auto& group_key = group_md.first; encode(group_key.first, bl); // pool encode(group_key.second, bl); // group encode(group_md.second, bl, features); } ENCODE_FINISH(bl); } inline void decode( std::map& gmetadata, ceph::buffer::list::const_iterator &bl) { gmetadata.clear(); uint32_t ngroups; DECODE_START(1, bl); decode(ngroups, bl); for (uint32_t i = 0; i