Skip to content

Commit 96c7fc7

Browse files
Ravi Nagarjun AkellaRavi Nagarjun Akella
authored andcommitted
read API implementation
1 parent 6af2b03 commit 96c7fc7

File tree

10 files changed

+213
-66
lines changed

10 files changed

+213
-66
lines changed

conanfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class HomeBlocksConan(ConanFile):
1111
name = "homeblocks"
12-
version = "1.0.16"
12+
version = "1.0.17"
1313
homepage = "https://github.com/eBay/HomeBlocks"
1414
description = "Block Store built on HomeStore"
1515
topics = ("ebay")

src/include/homeblks/volume_mgr.hpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct vol_interface_req : public sisl::ObjLifeCounter< vol_interface_req > {
3636

3737
virtual ~vol_interface_req() = default; // override; sisl::ObjLifeCounter should have virtual destructor
3838
virtual void free_yourself() { delete this; }
39+
lba_t end_lba() const { return lba + nlbas - 1; }
3940
};
4041

4142
using vol_interface_req_ptr = boost::intrusive_ptr< vol_interface_req >;
@@ -95,29 +96,27 @@ class VolumeManager : public Manager< VolumeError > {
9596
*
9697
* @param vol Pointer to the volume
9798
* @param req Request created which contains all the write parameters
98-
* @param part_of_batch Is this request part of a batch request. If so, implementation can wait for batch_submit
99+
* req.part_of_batch field can be used if this request is part of a batch request. If so, implementation can wait for batch_submit
99100
* call before issuing the writes. IO might already be started or even completed (in case of errors) before
100101
* batch_sumbit call, so application cannot assume IO will be started only after submit_batch call.
101102
*
102103
* @return std::error_condition no_error or error in issuing writes
103104
*/
104-
virtual NullAsyncResult write(const VolumePtr& vol, const vol_interface_req_ptr& req,
105-
bool part_of_batch = false) = 0;
105+
virtual NullAsyncResult write(const VolumePtr& vol, const vol_interface_req_ptr& req) = 0;
106106

107107
/**
108108
* @brief Read the data from the volume asynchronously, created from the request. After completion the attached
109109
* callback function will be called with this req ptr.
110110
*
111111
* @param vol Pointer to the volume
112112
* @param req Request created which contains all the read parameters
113-
* @param part_of_batch Is this request part of a batch request. If so, implementation can wait for batch_submit
113+
* req.part_of_batch field can be used if this request is part of a batch request. If so, implementation can wait for batch_submit
114114
* call before issuing the reads. IO might already be started or even completed (in case of errors) before
115115
* batch_sumbit call, so application cannot assume IO will be started only after submit_batch call.
116116
*
117117
* @return std::error_condition no_error or error in issuing reads
118118
*/
119-
virtual NullAsyncResult read(const VolumePtr& vol, const vol_interface_req_ptr& req,
120-
bool part_of_batch = false) = 0;
119+
virtual NullAsyncResult read(const VolumePtr& vol, const vol_interface_req_ptr& req) = 0;
121120

122121
/**
123122
* @brief unmap the given block range

src/lib/homeblks_impl.hpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,26 +105,14 @@ class HomeBlocksImpl : public HomeBlocks, public VolumeManager, public std::enab
105105

106106
VolumePtr lookup_volume(const volume_id_t& id) final;
107107

108-
NullAsyncResult write(const VolumePtr& vol, const vol_interface_req_ptr& req, bool part_of_batch = false) final;
108+
NullAsyncResult write(const VolumePtr& vol, const vol_interface_req_ptr& req) final;
109109

110-
NullAsyncResult read(const VolumePtr& vol, const vol_interface_req_ptr& req, bool part_of_batch = false) final;
110+
NullAsyncResult read(const VolumePtr& vol, const vol_interface_req_ptr& req) final;
111111

112112
NullAsyncResult unmap(const VolumePtr& vol, const vol_interface_req_ptr& req) final;
113113

114114
void submit_io_batch() final;
115115

116-
117-
NullAsyncResult write(const VolumePtr& vol, const vol_interface_req_ptr& req,
118-
bool part_of_batch = false) final;
119-
120-
NullAsyncResult read(const VolumePtr& vol, const vol_interface_req_ptr& req,
121-
bool part_of_batch = false) final;
122-
123-
NullAsyncResult unmap(const VolumePtr& vol, const vol_interface_req_ptr& req) final;
124-
125-
void submit_io_batch() final;
126-
127-
128116
// see api comments in base class;
129117
bool get_stats(volume_id_t id, VolumeStats& stats) const final;
130118
void get_volume_ids(std::vector< volume_id_t >& vol_ids) const final;
@@ -160,6 +148,8 @@ class HomeBlocksImpl : public HomeBlocks, public VolumeManager, public std::enab
160148

161149
VolumeManager::Result< folly::Unit > write_to_index(const VolumePtr& vol_ptr, lba_t start_lba, lba_t end_lba,
162150
std::unordered_map< lba_t, BlockInfo >& blocks_info);
151+
VolumeManager::Result< folly::Unit > read_from_index(const VolumePtr& vol_ptr, const vol_interface_req_ptr& req,
152+
std::vector< std::pair< VolumeIndexKey, VolumeIndexValue > >& out_vector);
163153
};
164154

165155
class HBIndexSvcCB : public homestore::IndexServiceCallbacks {

src/lib/index.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ HomeBlocksImpl::write_to_index(const VolumePtr& vol_ptr, lba_t start_lba, lba_t
3333
// For value shift() will get the blk_num and checksum for each lba.
3434
IndexValueContext app_ctx{&blocks_info, start_lba};
3535
const BlkId& start_blkid = blocks_info[start_lba].new_blkid;
36-
VolumeIndexValue value{start_blkid};
36+
VolumeIndexValue value{start_blkid, blocks_info[start_lba].checksum};
3737

3838
auto req = homestore::BtreeRangePutRequest< VolumeIndexKey >{
3939
homestore::BtreeKeyRange< VolumeIndexKey >{VolumeIndexKey{start_lba}, true, VolumeIndexKey{end_lba}, true},
@@ -51,4 +51,16 @@ HomeBlocksImpl::write_to_index(const VolumePtr& vol_ptr, lba_t start_lba, lba_t
5151
return folly::Unit();
5252
}
5353

54+
VolumeManager::Result< folly::Unit > HomeBlocksImpl::read_from_index(const VolumePtr& vol_ptr, const vol_interface_req_ptr& req,
55+
std::vector< std::pair< VolumeIndexKey, VolumeIndexValue > >& out_vector) {
56+
homestore::BtreeQueryRequest< VolumeIndexKey > qreq{homestore::BtreeKeyRange< VolumeIndexKey >{VolumeIndexKey{req->lba},
57+
VolumeIndexKey{req->end_lba()}}, homestore::BtreeQueryType::SWEEP_NON_INTRUSIVE_PAGINATION_QUERY};
58+
auto index_table = vol_ptr->indx_table();
59+
RELEASE_ASSERT(index_table != nullptr, "Index table is null for volume id: {}", boost::uuids::to_string(vol_ptr->id()));
60+
if (auto ret = index_table->query(qreq, out_vector); ret != homestore::btree_status_t::success) {
61+
return folly::makeUnexpected(VolumeError::INDEX_ERROR);
62+
}
63+
return folly::Unit();
64+
}
65+
5466
} // namespace homeblocks

src/lib/tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ target_sources(test_fixture PRIVATE
66
)
77
target_link_libraries(test_fixture
88
${COMMON_TEST_DEPS}
9-
)
9+
)

src/lib/volume/index.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,18 @@ class VolumeIndexValue : public homestore::BtreeIntervalValue {
188188
#pragma pack()
189189

190190
public:
191-
VolumeIndexValue(const BlkId& base_blkid) : homestore::BtreeIntervalValue() {
191+
VolumeIndexValue(const BlkId& base_blkid, homestore::csum_t csum) : homestore::BtreeIntervalValue() {
192192
m_blkid_suffix = uint32_cast(base_blkid.to_integer() & 0xFFFFFFFF) >> 1;
193193
m_blkid_prefix = uint32_cast(base_blkid.to_integer() >> 32);
194+
m_checksum = csum;
194195
}
196+
VolumeIndexValue(const BlkId& base_blkid) : VolumeIndexValue(base_blkid, 0) {}
195197
VolumeIndexValue() = default;
196198
VolumeIndexValue(const VolumeIndexValue& other) :
197199
homestore::BtreeIntervalValue(),
198200
m_blkid_prefix(other.m_blkid_prefix),
199-
m_blkid_suffix(other.m_blkid_suffix) {}
201+
m_blkid_suffix(other.m_blkid_suffix),
202+
m_checksum(other.m_checksum) {}
200203
VolumeIndexValue(const sisl::blob& b, bool copy) : homestore::BtreeIntervalValue() { this->deserialize(b, copy); }
201204
virtual ~VolumeIndexValue() = default;
202205

@@ -249,7 +252,7 @@ class VolumeIndexValue : public homestore::BtreeIntervalValue {
249252
// Get the next blk num and checksum
250253
m_blkid_suffix += n;
251254
auto curr_lba = ctx->start_lba + n;
252-
LOGINFO("shift n={} blk_num={} curr_lba={}", n, m_blkid_suffix, curr_lba);
255+
LOGTRACE("shift n={} blk_num={} curr_lba={}", n, m_blkid_suffix, curr_lba);
253256
DEBUG_ASSERT(ctx->block_info->find(curr_lba) != ctx->block_info->end(), "Invalid index");
254257
m_checksum = (*ctx->block_info)[curr_lba].checksum;
255258
}
@@ -281,4 +284,4 @@ class VolumeIndexValue : public homestore::BtreeIntervalValue {
281284
(m_checksum == other.m_checksum));
282285
}
283286
};
284-
} // namespace homeblocks
287+
} // namespace homeblocks

src/lib/volume/tests/test_common.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,12 @@ class HBTestHelper {
213213
}
214214
}
215215

216+
static void validate_zeros(uint8_t const* buf, uint64_t size) {
217+
sisl::io_blob_safe blob(size, 512);
218+
std::memset(blob.bytes(), 0, size);
219+
RELEASE_ASSERT_EQ(std::memcmp(buf, blob.bytes(), size), 0, "data_buf mismatch");
220+
}
221+
216222
private:
217223
void init_devices(bool is_file, uint64_t dev_size = 0) {
218224
if (is_file) {
@@ -277,4 +283,4 @@ class HBTestHelper {
277283
Waiter waiter_;
278284
};
279285

280-
} // namespace test_common
286+
} // namespace test_common

src/lib/volume/tests/test_volume.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
SISL_LOGGING_INIT(HOMEBLOCKS_LOG_MODS)
2828
SISL_OPTION_GROUP(test_volume_setup,
29-
(num_vols, "", "num_vols", "number of volumes", ::cxxopts::value< uint32_t >()->default_value("2"),
30-
"number"));
29+
(num_vols, "", "num_vols", "number of volumes", ::cxxopts::value< uint32_t >()->default_value("2"),
30+
"number"));
3131
SISL_OPTIONS_ENABLE(logging, test_common_setup, test_volume_setup, homeblocks)
3232
SISL_LOGGING_DECL(test_volume)
3333

@@ -193,4 +193,4 @@ int main(int argc, char* argv[]) {
193193
g_helper->teardown();
194194

195195
return ret;
196-
}
196+
}

src/lib/volume/tests/test_volume_io.cpp

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class VolumeIOImpl {
9696
data_bytes += page_size;
9797
// Store the lba to pattern mapping
9898
m_lba_data[lba] = data_pattern;
99-
LOGINFO("Generate data lba={} pattern={}", lba, data_pattern);
99+
//LOGDEBUG("Generate data lba={} pattern={}", lba, data_pattern);
100100
lba++;
101101
}
102102

@@ -131,18 +131,44 @@ class VolumeIOImpl {
131131
});
132132
}
133133

134-
void verify_data() {
135-
for (auto& [lba, data_pattern] : m_lba_data) {
136-
auto buffer = iomanager.iobuf_alloc(512, 4096);
137-
vol_interface_req_ptr req(new vol_interface_req{buffer, lba, 1});
134+
void read_and_verify(lba_t start_lba, uint32_t nlbas) {
135+
auto sz = nlbas * m_vol_ptr->info()->page_size;
136+
sisl::io_blob_safe read_blob(sz, 512);
137+
auto buf = read_blob.bytes();
138+
vol_interface_req_ptr req(new vol_interface_req{buf, start_lba, nlbas});
139+
auto read_resp = g_helper->inst()->volume_manager()->read(m_vol_ptr, req).get();
140+
if(read_resp.hasError()) {
141+
LOGERROR("Read failed with error={}", read_resp.error());
142+
}
143+
RELEASE_ASSERT(!read_resp.hasError(), "Read failed with error={}", read_resp.error());
144+
auto read_sz = m_vol_ptr->info()->page_size;
145+
for(auto lba = start_lba; lba < start_lba + nlbas; lba++, buf += read_sz) {
146+
uint64_t data_pattern = 0;
147+
if(auto it = m_lba_data.find(lba); it != m_lba_data.end()) {
148+
data_pattern = it->second;
149+
test_common::HBTestHelper::validate_data_buf(buf, m_vol_ptr->info()->page_size, data_pattern);
150+
} else {
151+
test_common::HBTestHelper::validate_zeros(buf, m_vol_ptr->info()->page_size);
152+
}
153+
154+
LOGDEBUG("Verify data lba={} pattern expected={} actual={}", lba, data_pattern, *r_cast< uint64_t* >(read_blob.bytes()));
155+
}
156+
}
138157

139-
auto vol_mgr = g_helper->inst()->volume_manager();
140-
vol_mgr->read(m_vol_ptr, req).get();
141-
// LOGINFO("Data read={}", fmt::format("{}", spdlog::to_hex((buffer), (buffer) + (128))));
142-
test_common::HBTestHelper::validate_data_buf(buffer, 4096, data_pattern);
143-
LOGINFO("Verify data lba={} pattern={} {}", lba, data_pattern, *r_cast< uint64_t* >(buffer));
144-
iomanager.iobuf_free(buffer);
158+
void verify_data(uint64_t nlbas_per_io = 1) {
159+
auto start_lba = m_lba_data.begin()->first;
160+
auto max_lba = m_lba_data.rbegin()->first;
161+
verify_data(start_lba, max_lba, nlbas_per_io);
162+
}
163+
164+
void verify_data(lba_t start_lba, lba_t max_lba, uint64_t nlbas_per_io) {
165+
uint64_t num_lbas_verified = 0;
166+
for(auto lba = start_lba; lba < max_lba; lba += nlbas_per_io) {
167+
auto num_lbas_this_round = std::min(nlbas_per_io, max_lba - lba);
168+
read_and_verify(lba, num_lbas_this_round);
169+
num_lbas_verified += num_lbas_this_round;
145170
}
171+
LOGINFO("Verified {} lbas for volume {}", num_lbas_verified, m_vol_ptr->info()->name);
146172
}
147173

148174
#ifdef _PRERELEASE
@@ -191,22 +217,21 @@ class VolumeIOTest : public ::testing::Test {
191217
// Get a random volume.
192218
vol = m_vols_impl[rand() % m_vols_impl.size()];
193219
}
194-
195220
vol->generate_io(start_lba, nblks);
196221
});
197222

198223
if (wait) { g_helper->runner().execute().get(); }
199224
LOGINFO("IO completed");
200225
}
201226

202-
void verify_data(shared< VolumeIOImpl > vol_impl = nullptr) {
227+
void verify_data(shared< VolumeIOImpl > vol_impl = nullptr, uint64_t nlbas_per_io = 1) {
203228
if (vol_impl) {
204-
vol_impl->verify_data();
229+
vol_impl->verify_data(nlbas_per_io);
205230
return;
206231
}
207232

208233
for (auto& vol_impl : m_vols_impl) {
209-
vol_impl->verify_data();
234+
vol_impl->verify_data(nlbas_per_io);
210235
}
211236
}
212237

@@ -233,18 +258,38 @@ TEST_F(VolumeIOTest, SingleVolumeWriteData) {
233258
vol->reset();
234259

235260
LOGINFO("Verify data");
236-
verify_data(vol);
261+
verify_data(vol, 30 /* nlbas_per_io */);
237262

238263
// Write and verify again on same LBA range to single volume multiple times.
239264
LOGINFO("Write and verify data with num_iter={} start={} nblks={}", num_iter, start_lba, nblks);
240265
for (uint32_t i = 0; i < num_iter; i++) {
241266
generate_io_single(vol, start_lba, nblks);
242267
}
243-
244268
verify_data(vol);
269+
270+
// verify random lba ranges
271+
245272
LOGINFO("SingleVolumeWriteData test done.");
246273
}
247274

275+
TEST_F(VolumeIOTest, SingleVolumeReadData) {
276+
// Write and verify fixed LBA range to single volume multiple times.
277+
auto vol = volume_list().back();
278+
uint32_t nblks = 500;
279+
lba_t start_lba = 1000;
280+
uint32_t num_iter = 1;
281+
LOGINFO("Write and verify data with num_iter={} start={} nblks={}", num_iter, start_lba, nblks);
282+
for (uint32_t i = 0; i < num_iter; i++) {
283+
generate_io_single(vol, start_lba, nblks);
284+
}
285+
286+
vol->verify_data(300, 800, 40);
287+
vol->verify_data(2000, 3000, 40);
288+
vol->verify_data(800, 1800, 40);
289+
290+
LOGINFO("SingleVolumeReadHoles test done.");
291+
}
292+
248293
TEST_F(VolumeIOTest, MultipleVolumeWriteData) {
249294
LOGINFO("Write data randomly on num_vols={} num_io={}", SISL_OPTIONS["num_vols"].as< uint32_t >(),
250295
SISL_OPTIONS["num_io"].as< uint64_t >());

0 commit comments

Comments
 (0)