|
| 1 | +#include <algorithm> |
| 2 | + |
| 3 | +#include <iomgr/io_environment.hpp> |
| 4 | +#include <homestore/homestore.hpp> |
| 5 | +#include <homestore/replication_service.hpp> |
| 6 | +#include <sisl/options/options.h> |
| 7 | +#include "homeblks_impl.hpp" |
| 8 | +#include "listener.hpp" |
| 9 | + |
| 10 | +SISL_OPTION_GROUP(homeblocks, |
| 11 | + (executor_type, "", "executor", "Executor to use for Future deferal", |
| 12 | + ::cxxopts::value< std::string >()->default_value("immediate"), "immediate|cpu|io")); |
| 13 | + |
| 14 | +SISL_LOGGING_DEF(HOMEBLOCKS_LOG_MODS) |
| 15 | + |
| 16 | +namespace homeblocks { |
| 17 | + |
| 18 | +extern std::shared_ptr< HomeBlocks > init_homeobject(std::weak_ptr< HomeBlocksApplication >&& application) { |
| 19 | + LOGI("Initializing HomeBlocks"); |
| 20 | + auto inst = std::make_shared< HomeBlocksImpl >(std::move(application)); |
| 21 | + inst->init_homestore(); |
| 22 | + inst->init_cp(); |
| 23 | + return inst; |
| 24 | +} |
| 25 | + |
| 26 | +HomeBlocksStats HomeBlocksImpl::get_stats() const { |
| 27 | + HomeBlocksStats s; |
| 28 | + return s; |
| 29 | +} |
| 30 | + |
| 31 | +HomeBlocksImpl::HomeBlocksImpl(std::weak_ptr< HomeBlocksApplication >&& application) : |
| 32 | + _application(std::move(application)) { |
| 33 | + auto exe_type = SISL_OPTIONS["executor"].as< std::string >(); |
| 34 | + std::transform(exe_type.begin(), exe_type.end(), exe_type.begin(), ::tolower); |
| 35 | + |
| 36 | + if ("immediate" == exe_type) [[likely]] |
| 37 | + executor_ = &folly::QueuedImmediateExecutor::instance(); |
| 38 | + else if ("io" == exe_type) |
| 39 | + executor_ = folly::getGlobalIOExecutor(); |
| 40 | + else if ("cpu" == exe_type) |
| 41 | + executor_ = folly::getGlobalCPUExecutor(); |
| 42 | + else |
| 43 | + RELEASE_ASSERT(false, "Unknown Folly Executor type: [{}]", exe_type); |
| 44 | + LOGI("initialized with [executor={}]", exe_type); |
| 45 | +} |
| 46 | + |
| 47 | +DevType HomeBlocksImpl::get_device_type(std::string const& devname) { |
| 48 | + const iomgr::drive_type dtype = iomgr::DriveInterface::get_drive_type(devname); |
| 49 | + if (dtype == iomgr::drive_type::block_hdd || dtype == iomgr::drive_type::file_on_hdd) { return DevType::HDD; } |
| 50 | + if (dtype == iomgr::drive_type::file_on_nvme || dtype == iomgr::drive_type::block_nvme) { return DevType::NVME; } |
| 51 | + return DevType::UNSUPPORTED; |
| 52 | +} |
| 53 | + |
| 54 | +// repl application to init homestore |
| 55 | +class HBReplApp : public homestore::ReplApplication { |
| 56 | +public: |
| 57 | + HBReplApp(homestore::repl_impl_type impl_type, bool tl_consistency, HomeBlocksImpl* hb, |
| 58 | + std::weak_ptr< HomeBlocksApplication > ho_app) : |
| 59 | + impl_type_(impl_type), tl_consistency_(tl_consistency), hb_(hb), ho_app_(ho_app) {} |
| 60 | + |
| 61 | + // TODO: make this override after the base class in homestore adds a virtual destructor |
| 62 | + virtual ~HBReplApp() = default; |
| 63 | + |
| 64 | + // overrides |
| 65 | + homestore::repl_impl_type get_impl_type() const override { return impl_type_; } |
| 66 | + |
| 67 | + bool need_timeline_consistency() const override { return tl_consistency_; } |
| 68 | + |
| 69 | + // this will be called by homestore when create_repl_dev is called; |
| 70 | + std::shared_ptr< homestore::ReplDevListener > create_repl_dev_listener(homestore::group_id_t group_id) override { |
| 71 | + return std::make_shared< HBListener >(hb_); |
| 72 | +#if 0 |
| 73 | + std::scoped_lock lock_guard(_repl_sm_map_lock); |
| 74 | + auto [it, inserted] = _repl_sm_map.emplace(group_id, nullptr); |
| 75 | + if (inserted) { it->second = std::make_shared< ReplicationStateMachine >(hb_); } |
| 76 | + return it->second; |
| 77 | +#endif |
| 78 | + } |
| 79 | + |
| 80 | + void on_repl_devs_init_completed() override { hb_->on_init_complete(); } |
| 81 | + |
| 82 | + std::pair< std::string, uint16_t > lookup_peer(homestore::replica_id_t uuid) const override { |
| 83 | + // r1: should never come here; |
| 84 | + RELEASE_ASSERT(false, "Unexpected to be called."); |
| 85 | + return std::make_pair("", 0); |
| 86 | + } |
| 87 | + |
| 88 | + homestore::replica_id_t get_my_repl_id() const override { return hb_->our_uuid(); } |
| 89 | + |
| 90 | +private: |
| 91 | + homestore::repl_impl_type impl_type_; |
| 92 | + bool tl_consistency_; // indicates whether this application needs timeline consistency; |
| 93 | + HomeBlocksImpl* hb_; |
| 94 | + std::weak_ptr< HomeBlocksApplication > ho_app_; |
| 95 | +#if 0 |
| 96 | + std::map< homestore::group_id_t, std::shared_ptr< HBListener> > _repl_sm_map; |
| 97 | + std::mutex _repl_sm_map_lock; |
| 98 | +#endif |
| 99 | +}; |
| 100 | + |
| 101 | +void HomeBlocksImpl::get_dev_info(shared< HomeBlocksApplication > app, std::vector< homestore::dev_info >& dev_info, |
| 102 | + bool& has_data_dev, bool& has_fast_dev) { |
| 103 | + for (auto const& dev : app->devices()) { |
| 104 | + auto input_dev_type = dev.type; |
| 105 | + auto detected_type = get_device_type(dev.path.string()); |
| 106 | + LOGD("Device {} detected as {}", dev.path.string(), detected_type); |
| 107 | + auto final_type = (dev.type == DevType::AUTO_DETECT) ? detected_type : input_dev_type; |
| 108 | + if (final_type == DevType::UNSUPPORTED) { |
| 109 | + LOGW("Device {} is not supported, skipping", dev.path.string()); |
| 110 | + continue; |
| 111 | + } |
| 112 | + if (input_dev_type != DevType::AUTO_DETECT && detected_type != final_type) { |
| 113 | + LOGW("Device {} detected as {}, but input type is {}, using input type", dev.path.string(), detected_type, |
| 114 | + input_dev_type); |
| 115 | + } |
| 116 | + auto hs_type = (final_type == DevType::HDD) ? homestore::HSDevType::Data : homestore::HSDevType::Fast; |
| 117 | + if (hs_type == homestore::HSDevType::Data) { has_data_dev = true; } |
| 118 | + if (hs_type == homestore::HSDevType::Fast) { has_fast_dev = true; } |
| 119 | + dev_info.emplace_back(std::filesystem::canonical(dev.path).string(), hs_type); |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +void HomeBlocksImpl::init_homestore() { |
| 124 | + auto app = _application.lock(); |
| 125 | + RELEASE_ASSERT(app, "HomeObjectApplication lifetime unexpected!"); |
| 126 | + |
| 127 | + LOGI("Starting iomgr with {} threads, spdk: {}", app->threads(), false); |
| 128 | + ioenvironment.with_iomgr(iomgr::iomgr_params{.num_threads = app->threads(), .is_spdk = app->spdk_mode()}) |
| 129 | + .with_http_server(); |
| 130 | + |
| 131 | + const uint64_t app_mem_size = app->app_mem_size(); |
| 132 | + LOGI("Initialize and start HomeStore with app_mem_size = {}", app_mem_size); |
| 133 | + |
| 134 | + std::vector< homestore::dev_info > device_info; |
| 135 | + bool has_data_dev{false}, has_fast_dev{false}; |
| 136 | + get_dev_info(app, device_info, has_data_dev, has_fast_dev); |
| 137 | + |
| 138 | + RELEASE_ASSERT(device_info.size() != 0, "No supported devices found!"); |
| 139 | + using namespace homestore; |
| 140 | + // Note: timeline_consistency doesn't matter as we are using solo repl dev; |
| 141 | + auto repl_app = |
| 142 | + std::make_shared< HBReplApp >(repl_impl_type::solo, false /*timeline_consistency*/, this, _application); |
| 143 | + bool need_format = HomeStore::instance() |
| 144 | + ->with_index_service(std::make_unique< HBIndexSvcCB >(this)) |
| 145 | + .with_repl_data_service(repl_app) // chunk selector defaulted to round_robine |
| 146 | + .start(hs_input_params{.devices = device_info, .app_mem_size = app_mem_size}, |
| 147 | + [this]() { register_metablk_cb(); }); |
| 148 | + if (need_format) { |
| 149 | + LOGI("We are starting for the first time. Formatting HomeStore. "); |
| 150 | + if (has_data_dev && has_fast_dev) { |
| 151 | + // NOTE: chunk_size, num_chunks only has to specify one, can be deduced from each other. |
| 152 | + HomeStore::instance()->format_and_start({ |
| 153 | + {HS_SERVICE::META, hs_format_params{.dev_type = HSDevType::Fast, .size_pct = 9.0}}, |
| 154 | + {HS_SERVICE::LOG, |
| 155 | + hs_format_params{ |
| 156 | + .dev_type = HSDevType::Fast, .size_pct = 45.0, .num_chunks = 0, .chunk_size = 32 * Mi}}, |
| 157 | + {HS_SERVICE::INDEX, hs_format_params{.dev_type = HSDevType::Fast, .size_pct = 45.0}}, |
| 158 | + {HS_SERVICE::REPLICATION, |
| 159 | + hs_format_params{.dev_type = HSDevType::Data, |
| 160 | + .size_pct = 95.0, |
| 161 | + .num_chunks = 0, // num_chunks will be deduced from chunk_size |
| 162 | + .chunk_size = HS_CHUNK_SIZE, |
| 163 | + .block_size = DATA_BLK_SIZE}}, |
| 164 | + }); |
| 165 | + } else { |
| 166 | + auto run_on_type = has_fast_dev ? homestore::HSDevType::Fast : homestore::HSDevType::Data; |
| 167 | + LOGD("Running with Single mode, all service on {}", run_on_type); |
| 168 | + HomeStore::instance()->format_and_start({ |
| 169 | + {HS_SERVICE::META, hs_format_params{.dev_type = run_on_type, .size_pct = 5.0}}, |
| 170 | + {HS_SERVICE::LOG, |
| 171 | + hs_format_params{.dev_type = run_on_type, .size_pct = 10.0, .num_chunks = 0, .chunk_size = 32 * Mi}}, |
| 172 | + {HS_SERVICE::INDEX, hs_format_params{.dev_type = run_on_type, .size_pct = 5.0}}, |
| 173 | + {HS_SERVICE::REPLICATION, |
| 174 | + hs_format_params{.dev_type = run_on_type, |
| 175 | + .size_pct = 75.0, |
| 176 | + .num_chunks = 0, // num_chunks will be deduced from chunk_size; |
| 177 | + .chunk_size = HS_CHUNK_SIZE, |
| 178 | + .block_size = DATA_BLK_SIZE}}, |
| 179 | + }); |
| 180 | + } |
| 181 | + repl_app->on_repl_devs_init_completed(); |
| 182 | + superblk_init(); |
| 183 | + } |
| 184 | + |
| 185 | + recovery_done_ = true; |
| 186 | + LOGI("Initialize and start HomeStore is successfully"); |
| 187 | +} |
| 188 | + |
| 189 | +void HomeBlocksImpl::superblk_init() { |
| 190 | + sb_ = homestore::superblk< homeblks_sb_t >(HB_META_NAME); |
| 191 | + sb_.create(sizeof(homeblks_sb_t)); |
| 192 | + sb_->magic = HB_SB_MAGIC; |
| 193 | + sb_->version = HB_SB_VER; |
| 194 | + sb_->boot_cnt = 0; |
| 195 | + sb_->init_flag(0); |
| 196 | + sb_.write(); |
| 197 | +} |
| 198 | + |
| 199 | +void HomeBlocksImpl::on_vol_meta_blk_found(sisl::byte_view const& buf, void* cookie) { |
| 200 | + // auto sb = homestore::superblk< vol_sb_t >(VOL_META_NAME); |
| 201 | + // sb.load(buf, cookie); |
| 202 | + // TODO: |
| 203 | +} |
| 204 | + |
| 205 | +void HomeBlocksImpl::on_hb_meta_blk_found(sisl::byte_view const& buf, void* cookie) { |
| 206 | + sb_ = homestore::superblk< homeblks_sb_t >(HB_META_NAME); |
| 207 | + sb_.load(buf, cookie); |
| 208 | + // sb verification |
| 209 | + RELEASE_ASSERT_EQ(sb_->version, HB_SB_VER); |
| 210 | + RELEASE_ASSERT_EQ(sb_->magic, HB_SB_MAGIC); |
| 211 | + |
| 212 | + if (sb_->test_flag(SB_FLAGS_GRACEFUL_SHUTDOWN)) { |
| 213 | + // if it is a gracefuln shutdown, this flag should be set again in shutdown routine; |
| 214 | + sb_->clear_flag(SB_FLAGS_GRACEFUL_SHUTDOWN); |
| 215 | + LOGI("System was shutdown gracefully"); |
| 216 | + } else { |
| 217 | + LOGI("System experienced sudden crash since last boot"); |
| 218 | + } |
| 219 | + |
| 220 | + ++sb_->boot_cnt; |
| 221 | + |
| 222 | + // avoid doing sb meta blk write in callback which will cause deadlock; |
| 223 | + // the 1st CP should flush all dirty SB before taking traffic; |
| 224 | +} |
| 225 | + |
| 226 | +void HomeBlocksImpl::register_metablk_cb() { |
| 227 | + // register some callbacks for metadata recovery; |
| 228 | + using namespace homestore; |
| 229 | + |
| 230 | + // HomeBlks SB |
| 231 | + HomeStore::instance()->meta_service().register_handler( |
| 232 | + HB_META_NAME, |
| 233 | + [this](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) { |
| 234 | + on_hb_meta_blk_found(std::move(buf), voidptr_cast(mblk)); |
| 235 | + }, |
| 236 | + nullptr /*recovery_comp_cb*/, true /* do_crc */); |
| 237 | + |
| 238 | + // Volume SB |
| 239 | + HomeStore::instance()->meta_service().register_handler( |
| 240 | + VOL_META_NAME, |
| 241 | + [this](homestore::meta_blk* mblk, sisl::byte_view buf, size_t size) { |
| 242 | + on_vol_meta_blk_found(std::move(buf), voidptr_cast(mblk)); |
| 243 | + }, |
| 244 | + nullptr /*recovery_comp_cb*/, true /* do_crc */); |
| 245 | +} |
| 246 | + |
| 247 | +void HomeBlocksImpl::on_init_complete() { |
| 248 | + // this is called after HomeStore all recovery completed. |
| 249 | + // Add anything that needs to be done here. |
| 250 | +} |
| 251 | + |
| 252 | +void HomeBlocksImpl::init_cp() {} |
| 253 | +} // namespace homeblocks |
0 commit comments