Skip to content

Commit 80bea2b

Browse files
author
Akanksha Mahajan
committed
Update stats for Read and ReadAsync in random_access_file_reader for async prefetching (#9810)
Summary: Update stats in random_access_file_reader for Read and ReadAsync API to take into account the read latency for async prefetching. It also fixes ERROR_HANDLER_AUTORESUME_RETRY_COUNT stat whose value was incorrect in portal.h Pull Request resolved: #9810 Test Plan: Update unit test Reviewed By: anand1976 Differential Revision: D35433081 Pulled By: akankshamahajan15 fbshipit-source-id: aeec3901270e58a003ce6b5214bd25ddcb3a12a9
1 parent 7115884 commit 80bea2b

File tree

7 files changed

+128
-10
lines changed

7 files changed

+128
-10
lines changed

file/prefetch_test.cc

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -694,8 +694,10 @@ TEST_P(PrefetchTest1, DBIterLevelReadAhead) {
694694
options.write_buffer_size = 1024;
695695
options.create_if_missing = true;
696696
options.compression = kNoCompression;
697+
options.statistics = CreateDBStatistics();
697698
options.env = env.get();
698-
if (std::get<0>(GetParam())) {
699+
bool use_direct_io = std::get<0>(GetParam());
700+
if (use_direct_io) {
699701
options.use_direct_reads = true;
700702
options.use_direct_io_for_flush_and_compaction = true;
701703
}
@@ -708,8 +710,7 @@ TEST_P(PrefetchTest1, DBIterLevelReadAhead) {
708710
options.table_factory.reset(NewBlockBasedTableFactory(table_options));
709711

710712
Status s = TryReopen(options);
711-
if (std::get<0>(GetParam()) &&
712-
(s.IsNotSupported() || s.IsInvalidArgument())) {
713+
if (use_direct_io && (s.IsNotSupported() || s.IsInvalidArgument())) {
713714
// If direct IO is not supported, skip the test
714715
return;
715716
} else {
@@ -766,22 +767,34 @@ TEST_P(PrefetchTest1, DBIterLevelReadAhead) {
766767
// TODO akanksha: Remove after adding new units.
767768
ro.async_io = true;
768769
}
770+
771+
ASSERT_OK(options.statistics->Reset());
769772
auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ro));
770773
int num_keys = 0;
771774
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
772775
ASSERT_OK(iter->status());
773776
num_keys++;
774777
}
775778
ASSERT_EQ(num_keys, total_keys);
776-
777779
ASSERT_GT(buff_prefetch_count, 0);
778-
buff_prefetch_count = 0;
779780
// For index and data blocks.
780781
if (is_adaptive_readahead) {
781782
ASSERT_EQ(readahead_carry_over_count, 2 * (num_sst_files - 1));
782783
} else {
783784
ASSERT_EQ(readahead_carry_over_count, 0);
784785
}
786+
787+
// Check stats to make sure async prefetch is done.
788+
{
789+
HistogramData async_read_bytes;
790+
options.statistics->histogramData(ASYNC_READ_BYTES, &async_read_bytes);
791+
if (ro.async_io && !use_direct_io) {
792+
ASSERT_GT(async_read_bytes.count, 0);
793+
} else {
794+
ASSERT_EQ(async_read_bytes.count, 0);
795+
}
796+
}
797+
785798
SyncPoint::GetInstance()->DisableProcessing();
786799
SyncPoint::GetInstance()->ClearAllCallBacks();
787800
}
@@ -902,6 +915,8 @@ TEST_P(PrefetchTest2, DecreaseReadAheadIfInCache) {
902915
options.use_direct_reads = true;
903916
options.use_direct_io_for_flush_and_compaction = true;
904917
}
918+
919+
options.statistics = CreateDBStatistics();
905920
BlockBasedTableOptions table_options;
906921
std::shared_ptr<Cache> cache = NewLRUCache(4 * 1024 * 1024, 2); // 8MB
907922
table_options.block_cache = cache;
@@ -948,7 +963,6 @@ TEST_P(PrefetchTest2, DecreaseReadAheadIfInCache) {
948963
SyncPoint::GetInstance()->EnableProcessing();
949964
ReadOptions ro;
950965
ro.adaptive_readahead = true;
951-
// TODO akanksha: Remove after adding new units.
952966
ro.async_io = true;
953967
{
954968
/*
@@ -964,7 +978,9 @@ TEST_P(PrefetchTest2, DecreaseReadAheadIfInCache) {
964978
iter->Seek(BuildKey(1019));
965979
buff_prefetch_count = 0;
966980
}
981+
967982
{
983+
ASSERT_OK(options.statistics->Reset());
968984
// After caching, blocks will be read from cache (Sequential blocks)
969985
auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ro));
970986
iter->Seek(BuildKey(0));
@@ -1008,6 +1024,18 @@ TEST_P(PrefetchTest2, DecreaseReadAheadIfInCache) {
10081024
ASSERT_TRUE(iter->Valid());
10091025
ASSERT_EQ(current_readahead_size, expected_current_readahead_size);
10101026
ASSERT_EQ(buff_prefetch_count, 2);
1027+
1028+
// Check stats to make sure async prefetch is done.
1029+
{
1030+
HistogramData async_read_bytes;
1031+
options.statistics->histogramData(ASYNC_READ_BYTES, &async_read_bytes);
1032+
if (GetParam()) {
1033+
ASSERT_EQ(async_read_bytes.count, 0);
1034+
} else {
1035+
ASSERT_GT(async_read_bytes.count, 0);
1036+
}
1037+
}
1038+
10111039
buff_prefetch_count = 0;
10121040
}
10131041
Close();
@@ -1033,6 +1061,7 @@ TEST_F(PrefetchTest2, ReadAsyncWithPosixFS) {
10331061
options.create_if_missing = true;
10341062
options.compression = kNoCompression;
10351063
options.env = env.get();
1064+
options.statistics = CreateDBStatistics();
10361065
if (use_direct_io) {
10371066
options.use_direct_reads = true;
10381067
options.use_direct_io_for_flush_and_compaction = true;
@@ -1080,6 +1109,7 @@ TEST_F(PrefetchTest2, ReadAsyncWithPosixFS) {
10801109
ro.adaptive_readahead = true;
10811110
ro.async_io = true;
10821111

1112+
ASSERT_OK(options.statistics->Reset());
10831113
auto iter = std::unique_ptr<Iterator>(db_->NewIterator(ro));
10841114
int num_keys = 0;
10851115
for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
@@ -1088,7 +1118,19 @@ TEST_F(PrefetchTest2, ReadAsyncWithPosixFS) {
10881118
}
10891119
ASSERT_EQ(num_keys, total_keys);
10901120
ASSERT_GT(buff_prefetch_count, 0);
1121+
1122+
// Check stats to make sure async prefetch is done.
1123+
{
1124+
HistogramData async_read_bytes;
1125+
options.statistics->histogramData(ASYNC_READ_BYTES, &async_read_bytes);
1126+
#if defined(ROCKSDB_IOURING_PRESENT)
1127+
ASSERT_GT(async_read_bytes.count, 0);
1128+
#else
1129+
ASSERT_EQ(async_read_bytes.count, 0);
1130+
#endif
1131+
}
10911132
}
1133+
10921134
SyncPoint::GetInstance()->DisableProcessing();
10931135
SyncPoint::GetInstance()->ClearAllCallBacks();
10941136

file/random_access_file_reader.cc

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,19 +425,75 @@ IOStatus RandomAccessFileReader::PrepareIOOptions(const ReadOptions& ro,
425425
}
426426
}
427427

428-
// TODO akanksha: Add perf_times etc.
428+
// TODO akanksha:
429+
// 1. Handle use_direct_io case which currently calls Read API.
429430
IOStatus RandomAccessFileReader::ReadAsync(
430431
FSReadRequest& req, const IOOptions& opts,
431432
std::function<void(const FSReadRequest&, void*)> cb, void* cb_arg,
432433
void** io_handle, IOHandleDeleter* del_fn,
433434
Env::IOPriority rate_limiter_priority) {
434435
if (use_direct_io()) {
436+
// For direct_io, it calls Read API.
435437
req.status = Read(opts, req.offset, req.len, &(req.result), req.scratch,
436438
nullptr /*dbg*/, rate_limiter_priority);
437439
cb(req, cb_arg);
438440
return IOStatus::OK();
439441
}
440-
return file_->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn,
441-
nullptr /*dbg*/);
442+
443+
// Create a callback and populate info.
444+
auto read_async_callback =
445+
std::bind(&RandomAccessFileReader::ReadAsyncCallback, this,
446+
std::placeholders::_1, std::placeholders::_2);
447+
ReadAsyncInfo* read_async_info = new ReadAsyncInfo;
448+
read_async_info->cb_ = cb;
449+
read_async_info->cb_arg_ = cb_arg;
450+
read_async_info->start_time_ = clock_->NowMicros();
451+
452+
#ifndef ROCKSDB_LITE
453+
if (ShouldNotifyListeners()) {
454+
read_async_info->fs_start_ts_ = FileOperationInfo::StartNow();
455+
}
456+
#endif
457+
458+
IOStatus s = file_->ReadAsync(req, opts, read_async_callback, read_async_info,
459+
io_handle, del_fn, nullptr /*dbg*/);
460+
if (!s.ok()) {
461+
delete read_async_info;
462+
}
463+
return s;
464+
}
465+
466+
void RandomAccessFileReader::ReadAsyncCallback(const FSReadRequest& req,
467+
void* cb_arg) {
468+
ReadAsyncInfo* read_async_info = static_cast<ReadAsyncInfo*>(cb_arg);
469+
assert(read_async_info);
470+
assert(read_async_info->cb_);
471+
472+
read_async_info->cb_(req, read_async_info->cb_arg_);
473+
474+
// Update stats and notify listeners.
475+
if (stats_ != nullptr && file_read_hist_ != nullptr) {
476+
// elapsed doesn't take into account delay and overwrite as StopWatch does
477+
// in Read.
478+
uint64_t elapsed = clock_->NowMicros() - read_async_info->start_time_;
479+
file_read_hist_->Add(elapsed);
480+
}
481+
if (req.status.ok()) {
482+
RecordInHistogram(stats_, ASYNC_READ_BYTES, req.result.size());
483+
}
484+
#ifndef ROCKSDB_LITE
485+
if (ShouldNotifyListeners()) {
486+
auto finish_ts = FileOperationInfo::FinishNow();
487+
NotifyOnFileReadFinish(req.offset, req.result.size(),
488+
read_async_info->fs_start_ts_, finish_ts,
489+
req.status);
490+
}
491+
if (!req.status.ok()) {
492+
NotifyOnIOError(req.status, FileOperationType::kRead, file_name(),
493+
req.result.size(), req.offset);
494+
}
495+
#endif
496+
RecordIOStats(stats_, file_temperature_, is_last_level_, req.result.size());
497+
delete read_async_info;
442498
}
443499
} // namespace ROCKSDB_NAMESPACE

file/random_access_file_reader.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ class RandomAccessFileReader {
9292
const Temperature file_temperature_;
9393
const bool is_last_level_;
9494

95+
struct ReadAsyncInfo {
96+
#ifndef ROCKSDB_LITE
97+
FileOperationInfo::StartTimePoint fs_start_ts_;
98+
#endif
99+
uint64_t start_time_;
100+
std::function<void(const FSReadRequest&, void*)> cb_;
101+
void* cb_arg_;
102+
};
103+
95104
public:
96105
explicit RandomAccessFileReader(
97106
std::unique_ptr<FSRandomAccessFile>&& raf, const std::string& _file_name,
@@ -179,5 +188,7 @@ class RandomAccessFileReader {
179188
std::function<void(const FSReadRequest&, void*)> cb,
180189
void* cb_arg, void** io_handle, IOHandleDeleter* del_fn,
181190
Env::IOPriority rate_limiter_priority);
191+
192+
void ReadAsyncCallback(const FSReadRequest& req, void* cb_arg);
182193
};
183194
} // namespace ROCKSDB_NAMESPACE

include/rocksdb/statistics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ enum Histograms : uint32_t {
534534
// Error handler statistics
535535
ERROR_HANDLER_AUTORESUME_RETRY_COUNT,
536536

537+
ASYNC_READ_BYTES,
538+
537539
HISTOGRAM_ENUM_MAX,
538540
};
539541

java/rocksjni/portal.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5551,7 +5551,9 @@ class HistogramTypeJni {
55515551
case ROCKSDB_NAMESPACE::Histograms::NUM_SST_READ_PER_LEVEL:
55525552
return 0x31;
55535553
case ROCKSDB_NAMESPACE::Histograms::ERROR_HANDLER_AUTORESUME_RETRY_COUNT:
5554-
return 0x31;
5554+
return 0x32;
5555+
case ROCKSDB_NAMESPACE::Histograms::ASYNC_READ_BYTES:
5556+
return 0x33;
55555557
case ROCKSDB_NAMESPACE::Histograms::HISTOGRAM_ENUM_MAX:
55565558
// 0x1F for backwards compatibility on current minor version.
55575559
return 0x1F;
@@ -5669,6 +5671,8 @@ class HistogramTypeJni {
56695671
case 0x32:
56705672
return ROCKSDB_NAMESPACE::Histograms::
56715673
ERROR_HANDLER_AUTORESUME_RETRY_COUNT;
5674+
case 0x33:
5675+
return ROCKSDB_NAMESPACE::Histograms::ASYNC_READ_BYTES;
56725676
case 0x1F:
56735677
// 0x1F for backwards compatibility on current minor version.
56745678
return ROCKSDB_NAMESPACE::Histograms::HISTOGRAM_ENUM_MAX;

java/src/main/java/org/rocksdb/HistogramType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ public enum HistogramType {
180180
*/
181181
ERROR_HANDLER_AUTORESUME_RETRY_COUNT((byte) 0x32),
182182

183+
ASYNC_READ_BYTES((byte) 0x33),
184+
183185
// 0x1F for backwards compatibility on current minor version.
184186
HISTOGRAM_ENUM_MAX((byte) 0x1F);
185187

monitoring/statistics.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ const std::vector<std::pair<Histograms, std::string>> HistogramsNameMap = {
283283
{NUM_SST_READ_PER_LEVEL, "rocksdb.num.sst.read.per.level"},
284284
{ERROR_HANDLER_AUTORESUME_RETRY_COUNT,
285285
"rocksdb.error.handler.autoresume.retry.count"},
286+
{ASYNC_READ_BYTES, "rocksdb.async.read.bytes"},
286287
};
287288

288289
std::shared_ptr<Statistics> CreateDBStatistics() {

0 commit comments

Comments
 (0)