Skip to content

Commit 23ba792

Browse files
authored
Initial commit for HomeBlks 2.0 (#42)
* Initial commit for HomeBlks 2.0 * update con ver * add remove_volume and lookup_volume api signature * add listener and init_homestore * homestore init * upgrade sisl ver * incorperate comment * add HB and vol meta svc register and recovery cb
1 parent 6112712 commit 23ba792

17 files changed

+544
-160
lines changed

conanfile.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class HomeBlocksConan(ConanFile):
1111
name = "homeblocks"
12-
version = "0.0.1"
12+
version = "0.0.2"
1313

1414
homepage = "https://github.com/eBay/HomeBlocks"
1515
description = "Block Store built on HomeStore"
@@ -44,8 +44,9 @@ def build_requirements(self):
4444
self.test_requires("gtest/1.14.0")
4545

4646
def requirements(self):
47-
self.requires("homestore/[~6.4, include_prerelease=True]@oss/master", transitive_headers=True)
48-
self.requires("sisl/[~12.2, include_prerelease=True]@oss/master", transitive_headers=True)
47+
self.requires("homestore/[^6.5]@oss/master")
48+
self.requires("iomgr/[^11.3]@oss/master")
49+
self.requires("sisl/[^12.3, include_prerelease=True]@oss/master", transitive_headers=True)
4950
self.requires("lz4/1.9.4", override=True)
5051

5152
def validate(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class HomeBlocksApplication {
4141
virtual bool spdk_mode() const = 0;
4242
virtual uint32_t threads() const = 0;
4343
virtual std::list< device_info_t > devices() const = 0;
44+
// in bytes;
45+
virtual uint64_t app_mem_size() const = 0;
4446

4547
// Callback made after determining if a SvcId exists or not during initialization, will consume response
4648
virtual peer_id_t discover_svcid(std::optional< peer_id_t > const& found) const = 0;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ struct VolumeInfo {
1717

1818
volume_id_t id;
1919
uint64_t size_bytes{0};
20+
uint64_t page_size{0};
21+
std::string vol_name;
2022

2123
auto operator<=>(VolumeInfo const& rhs) const {
2224
return boost::uuids::hash_value(id) <=> boost::uuids::hash_value(rhs.id);
2325
}
26+
2427
auto operator==(VolumeInfo const& rhs) const { return id == rhs.id; }
28+
29+
std::string to_string() {
30+
return fmt::format("VolumeInfo: id={} size_bytes={}, page_size={}, name={}", boost::uuids::to_string(id),
31+
size_bytes, page_size, vol_name);
32+
}
2533
};
2634

35+
using VolumeInfoPtr = std::shared_ptr< VolumeInfo >;
2736
struct VolumeStats {
2837
volume_id_t id;
2938

@@ -40,6 +49,12 @@ class VolumeManager : public Manager< VolumeError > {
4049
public:
4150
virtual NullAsyncResult create_volume(VolumeInfo&& volume_info) = 0;
4251

52+
virtual NullAsyncResult remove_volume(const volume_id_t& id) = 0;
53+
54+
virtual VolumeInfoPtr lookup_volume(const volume_id_t& id) = 0;
55+
56+
// TODO: read/write/unmap APIs
57+
4358
/**
4459
* Retrieves the statistics for a specific Volume identified by its ID.
4560
*

src/lib/CMakeLists.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ add_flags("-Wno-unused-parameter")
44

55
add_library(${PROJECT_NAME}_core OBJECT)
66
target_sources(${PROJECT_NAME}_core PRIVATE
7-
homeblocks_impl.cpp
8-
volume_manager.cpp
7+
homeblks_impl.cpp
8+
volume_mgr.cpp
9+
listener.cpp
910
)
1011
target_link_libraries(${PROJECT_NAME}_core
1112
${COMMON_DEPS}
1213
)
1314

1415
#add_subdirectory(homestore_backend)
15-
add_subdirectory(memory_backend)
16+
#add_subdirectory(memory_backend)
1617
add_subdirectory(tests)

src/lib/homeblks_impl.cpp

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
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

Comments
 (0)