Skip to content

Commit c73590e

Browse files
committed
[#15274] docdb: Fix wal_size metric to reflect on-disk size, include active segment
Summary: The `wal_size` metric reflects only the file size of readable log segments. `wal_size` is initialized to the size of all readable segments on `Log::Init()`, and only increased on the close of a current segment. This logic omits the size of the current active writable segment. This code change fixes the metric by tracking the active segment size at these stages: 1. Allocation 1. Growth during append 1. Truncation at close before transition to readable segment This change also introduces the APIs `WritableLogSegment::SizeOnDisk()` and `WritableFile::SizeOnDisk()` to get the true file size for the active segment, since the current `Size()` API returns the data size and not the file size. The test `TestLogMetrics` grows the log to six segments and verifies the `wal_size` metric against actual file-sizes. Jira: DB-4439 Test Plan: ```sh ./yb_build.sh --cxx-test='TEST_F(LogTest, TestLogMetrics) {' --test-args --vmodule=log=4 ./yb_build.sh --cxx-test='TEST_F(TestEnv, TestHolePunch) {' ./yb_build.sh --cxx-test='TEST_F(TestEnv, TestRWFile) {' ``` Jenkins Reviewers: yyan, rthallam, bkolagani, timur, sergei, mbautin, hector, qhu Reviewed By: yyan, sergei Subscribers: ybase, rthallam Tags: #jenkins-ready Differential Revision: https://phorge.dev.yugabyte.com/D46791
1 parent fca7e81 commit c73590e

File tree

8 files changed

+106
-30
lines changed

8 files changed

+106
-30
lines changed

src/yb/consensus/log-test.cc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -599,19 +599,26 @@ TEST_F(LogTest, TestLogMetrics) {
599599
ASSERT_OK(log_->GetLogReader()->GetSegmentsSnapshot(&segments));
600600
ASSERT_EQ(segments.size(), 1);
601601

602+
// Create at least 3 segments.
602603
while (segments.size() < 3) {
603604
ASSERT_OK(AppendNoOps(&op_id, kNumEntriesPerBatch));
604605
// Update the segments
605606
ASSERT_OK(log_->GetLogReader()->GetSegmentsSnapshot(&segments));
606607
}
607608

608-
ASSERT_OK(log_->Close());
609+
uint64_t metrics_wal_size = log_->metrics_->wal_size->value();
610+
uint64_t real_wal_size = 0;
609611

610-
int64_t wal_size_old = log_->metrics_->wal_size->value();
611-
BuildLog();
612-
int64_t wal_size_new = log_->metrics_->wal_size->value();
612+
for (const scoped_refptr<ReadableLogSegment>& segment : segments) {
613+
struct stat st;
614+
ASSERT_EQ(stat(segment->path().c_str(), &st), 0);
615+
uint64_t size_on_disk = st.st_size;
616+
real_wal_size += size_on_disk;
617+
LOG(INFO) << "Log size: " << size_on_disk << ", path: " << segment->path();
618+
}
613619

614-
ASSERT_EQ(wal_size_old, wal_size_new);
620+
ASSERT_OK(log_->Close());
621+
ASSERT_EQ(real_wal_size, metrics_wal_size);
615622
}
616623

617624
// Verify presence of min_start_time_running_txns in footer of closed segments.

src/yb/consensus/log.cc

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -752,11 +752,14 @@ Status Log::Init() {
752752
// In case where TServer process reboots, we need to reload the wal file size into the metric,
753753
// otherwise we do nothing
754754
if (metrics_ && metrics_->wal_size->value() == 0) {
755-
std::for_each(segments.begin(), segments.end(),
756-
[this](const auto& segment) {
757-
this->metrics_->wal_size->IncrementBy(segment->file_size());});
755+
for (const auto& segment : segments) {
756+
int64_t size = segment->file_size();
757+
this->metrics_->wal_size->IncrementBy(size);
758+
VLOG_WITH_PREFIX(4)
759+
<< "Incremented wal size by " << size
760+
<< " to " << this->metrics_->wal_size->value();
761+
}
758762
}
759-
760763
}
761764

762765
if (durable_wal_write_) {
@@ -815,9 +818,6 @@ Status Log::CloseCurrentSegment() {
815818
&footer_builder_);
816819
}
817820

818-
if (status.ok() && metrics_) {
819-
metrics_->wal_size->IncrementBy(active_segment_->Size());
820-
}
821821
return status;
822822
}
823823

@@ -986,17 +986,23 @@ Status Log::DoAppend(LogEntryBatch* entry_batch, SkipWalWrite skip_wal_write) {
986986
}
987987

988988
// If the size of this entry overflows the current segment, get a new one.
989+
bool segment_will_overflow =
990+
active_segment_->Size() + entry_batch_bytes + kEntryHeaderSize > cur_max_segment_size_;
989991
if (allocation_state() == SegmentAllocationState::kAllocationNotStarted) {
990-
if (active_segment_->Size() + entry_batch_bytes + kEntryHeaderSize > cur_max_segment_size_) {
992+
if (segment_will_overflow) {
991993
LOG_WITH_PREFIX(INFO) << "Max segment size " << cur_max_segment_size_ << " reached. "
992994
<< "Starting new segment allocation.";
993995
RETURN_NOT_OK(AsyncAllocateSegment());
994996
if (!options_.async_preallocate_segments) {
995997
RETURN_NOT_OK(RollOver());
998+
// Rollover prevents potential overflow.
999+
segment_will_overflow = false;
9961000
}
9971001
}
9981002
} else if (allocation_state() == SegmentAllocationState::kAllocationFinished) {
9991003
RETURN_NOT_OK(RollOver());
1004+
// Rollover prevents potential overflow.
1005+
segment_will_overflow = false;
10001006
} else {
10011007
VLOG_WITH_PREFIX(1) << "Segment allocation already in progress...";
10021008
}
@@ -1013,6 +1019,19 @@ Status Log::DoAppend(LogEntryBatch* entry_batch, SkipWalWrite skip_wal_write) {
10131019

10141020
if (metrics_) {
10151021
metrics_->bytes_logged->IncrementBy(active_segment_->written_offset() - start_offset);
1022+
VLOG_WITH_PREFIX(4) << "Total bytes logged: " << metrics_->bytes_logged->value();
1023+
1024+
// Check if append grew log file beyond pre-allocated size.
1025+
if (segment_will_overflow) {
1026+
int64_t size_on_disk = VERIFY_RESULT(active_segment_->SizeOnDisk());
1027+
if (size_on_disk != active_segment_ondisk_size_) {
1028+
metrics_->wal_size->IncrementBy(size_on_disk - active_segment_ondisk_size_);
1029+
VLOG_WITH_PREFIX(4)
1030+
<< "Incremented wal size by " << (size_on_disk - active_segment_ondisk_size_)
1031+
<< " to " << metrics_->wal_size->value();
1032+
active_segment_ondisk_size_ = size_on_disk;
1033+
}
1034+
}
10161035
}
10171036

10181037
// Populate the offset and sequence number for the entry batch if we did a WAL write.
@@ -1612,6 +1631,9 @@ Status Log::GC(int64_t min_op_idx, int32_t* num_gced) {
16121631

16131632
if (metrics_) {
16141633
metrics_->wal_size->IncrementBy(-1 * segment->file_size());
1634+
VLOG_WITH_PREFIX(4)
1635+
<< "Decremented wal size by " << segment->file_size()
1636+
<< " to " << metrics_->wal_size->value();
16151637
}
16161638
}
16171639

@@ -2054,6 +2076,17 @@ Status Log::SwitchToAllocatedSegment() {
20542076
read_wal_mem_tracker_));
20552077
RETURN_NOT_OK(readable_segment->Init(header, new_segment->first_entry_offset()));
20562078
RETURN_NOT_OK(reader_->AppendEmptySegment(readable_segment));
2079+
2080+
if (metrics_) {
2081+
// Add the pre-allocated segment size to metric.
2082+
int64_t segment_size = VERIFY_RESULT(new_segment->SizeOnDisk());
2083+
metrics_->wal_size->IncrementBy(segment_size);
2084+
active_segment_ondisk_size_ = segment_size;
2085+
VLOG_WITH_PREFIX(4)
2086+
<< "Incremented wal size by " << segment_size
2087+
<< " to " << metrics_->wal_size->value();
2088+
}
2089+
20572090
// Now set 'active_segment_' to the new segment.
20582091
{
20592092
std::lock_guard lock(active_segment_mutex_);
@@ -2083,6 +2116,17 @@ Status Log::ReplaceSegmentInReaderUnlocked() {
20832116
active_segment_->footer(),
20842117
active_segment_->first_entry_offset()));
20852118

2119+
if (metrics_) {
2120+
// The log may grow or truncate during close, hence update the log size metric before switching
2121+
// to the new segment.
2122+
int64_t size_on_disk = readable_segment->file_size();
2123+
metrics_->wal_size->IncrementBy(size_on_disk - active_segment_ondisk_size_);
2124+
VLOG_WITH_PREFIX(4)
2125+
<< "Incremented wal size by " << (size_on_disk - active_segment_ondisk_size_)
2126+
<< " to " << metrics_->wal_size->value();
2127+
active_segment_ondisk_size_ = 0;
2128+
}
2129+
20862130
return reader_->ReplaceLastSegment(readable_segment);
20872131
}
20882132

src/yb/consensus/log.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,9 @@ class Log : public RefCountedThreadSafe<Log> {
706706
std::function<int64_t(const std::string&)> get_xcluster_min_index_to_retain_
707707
GUARDED_BY(get_xcluster_index_lock_);
708708

709+
// Tracks on-disk size of active log segment file for metric reporting.
710+
int64_t active_segment_ondisk_size_ = 0;
711+
709712
DISALLOW_COPY_AND_ASSIGN(Log);
710713
};
711714

src/yb/consensus/log_util.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232

3333
#pragma once
3434

35+
#include <sys/stat.h>
36+
37+
#include <iosfwd>
38+
#include <map>
3539
#include <memory>
3640
#include <string>
3741
#include <vector>
@@ -443,6 +447,10 @@ class WritableLogSegment {
443447
return writable_file_->Size();
444448
}
445449

450+
Result<uint64_t> SizeOnDisk() const {
451+
return writable_file_->SizeOnDisk();
452+
}
453+
446454
// Appends the provided batch of data, including a header
447455
// and checksum.
448456
// Makes sure that the log segment has not been closed.

src/yb/util/env-test.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ TEST_F(TestEnv, TestHolePunch) {
480480
ASSERT_OK(file->Write(0, slice));
481481
ASSERT_OK(file->Sync());
482482
uint64_t sz;
483-
ASSERT_OK(file->Size(&sz));
483+
sz = ASSERT_RESULT(file->Size());
484484
ASSERT_EQ(kOneMb, sz);
485485
uint64_t size_on_disk = ASSERT_RESULT(env_->GetFileSizeOnDisk(test_path));
486486
// Some kernels and filesystems (e.g. Centos 6.6 with XFS) aggressively
@@ -492,7 +492,7 @@ TEST_F(TestEnv, TestHolePunch) {
492492
uint64_t punch_amount = 4096 * 4;
493493
uint64_t new_size_on_disk;
494494
ASSERT_OK(file->PunchHole(4096, punch_amount));
495-
ASSERT_OK(file->Size(&sz));
495+
sz = ASSERT_RESULT(file->Size());
496496
ASSERT_EQ(kOneMb, sz);
497497
new_size_on_disk = ASSERT_RESULT(env_->GetFileSizeOnDisk(test_path));
498498
ASSERT_EQ(size_on_disk - punch_amount, new_size_on_disk);
@@ -850,7 +850,7 @@ TEST_F(TestEnv, TestRWFile) {
850850
ASSERT_OK(file->Read(0, kTestData.length(), &result, scratch.get()));
851851
ASSERT_EQ(result, kTestData);
852852
uint64_t sz;
853-
ASSERT_OK(file->Size(&sz));
853+
sz = ASSERT_RESULT(file->Size());
854854
ASSERT_EQ(kTestData.length(), sz);
855855

856856
// Write past the end of the file and rewrite some of the interior.
@@ -863,7 +863,7 @@ TEST_F(TestEnv, TestRWFile) {
863863

864864
// Retest.
865865
ASSERT_EQ(result, kNewTestData);
866-
ASSERT_OK(file->Size(&sz));
866+
sz = ASSERT_RESULT(file->Size());
867867
ASSERT_EQ(kNewTestData.length(), sz);
868868

869869
// Make sure we can't overwrite it.

src/yb/util/env.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ class Env {
295295
// This should operate safely, not following any symlinks, etc.
296296
virtual Status DeleteRecursively(const std::string &dirname) = 0;
297297

298-
// Store the logical size of fname in *file_size.
298+
// Returns the logical size of fname.
299299
virtual Result<uint64_t> GetFileSize(const std::string& fname) = 0;
300300

301301
virtual Result<uint64_t> GetFileINode(const std::string& fname) = 0;
@@ -534,6 +534,9 @@ class WritableFile {
534534

535535
virtual uint64_t Size() const = 0;
536536

537+
// Get the logical file size visible to the users.
538+
virtual Result<uint64_t> SizeOnDisk() const = 0;
539+
537540
// Returns the filename provided when the WritableFile was constructed.
538541
virtual const std::string& filename() const = 0;
539542

@@ -563,6 +566,7 @@ class WritableFileWrapper : public WritableFile {
563566
Status Flush(FlushMode mode) override;
564567
Status Sync() override;
565568
uint64_t Size() const override { return target_->Size(); }
569+
Result<uint64_t> SizeOnDisk() const override { return target_->SizeOnDisk(); }
566570
const std::string& filename() const override { return target_->filename(); }
567571

568572
private:
@@ -649,7 +653,7 @@ class RWFile {
649653
virtual Status Close() = 0;
650654

651655
// Retrieves the file's size.
652-
virtual Status Size(uint64_t* size) const = 0;
656+
virtual Result<uint64_t> Size() const = 0;
653657

654658
// Returns the filename provided when the RWFile was constructed.
655659
virtual const std::string& filename() const = 0;

src/yb/util/env_posix.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,16 @@ static Status DoOpen(const string& filename, Env::CreateMode mode, int* fd, int
255255
return Status::OK();
256256
}
257257

258+
// Get logical on-disk file size using file descriptor.
259+
Result<uint64_t> GetLogicalFileSize(int fd, const string& filename) {
260+
ThreadRestrictions::AssertIOAllowed();
261+
struct stat st;
262+
if (fstat(fd, &st) == -1) {
263+
return STATUS_IO_ERROR(filename, errno);
264+
}
265+
return st.st_size;
266+
}
267+
258268
template <class Extractor>
259269
Result<uint64_t> GetFileStat(const std::string& fname, const char* event, Extractor extractor) {
260270
TRACE_EVENT1("io", event, "path", fname);
@@ -456,6 +466,11 @@ class PosixWritableFile : public WritableFile {
456466
return filesize_;
457467
}
458468

469+
Result<uint64_t> SizeOnDisk() const override {
470+
TRACE_EVENT1("io", "PosixWritableFile::SizeOnDisk", "path", filename_);
471+
return GetLogicalFileSize(fd_, filename_);
472+
}
473+
459474
const string& filename() const override { return filename_; }
460475

461476
protected:
@@ -922,15 +937,9 @@ class PosixRWFile final : public RWFile {
922937
return s;
923938
}
924939

925-
Status Size(uint64_t* size) const override {
940+
Result<uint64_t> Size() const override {
926941
TRACE_EVENT1("io", "PosixRWFile::Size", "path", filename_);
927-
ThreadRestrictions::AssertIOAllowed();
928-
struct stat st;
929-
if (fstat(fd_, &st) == -1) {
930-
return STATUS_IO_ERROR(filename_, errno);
931-
}
932-
*size = st.st_size;
933-
return Status::OK();
942+
return GetLogicalFileSize(fd_, filename_);
934943
}
935944

936945
const string& filename() const override {

src/yb/util/memenv/memenv.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class WritableFileImpl : public WritableFile {
118118

119119
uint64_t Size() const override { return file_->Size(); }
120120

121+
Result<uint64_t> SizeOnDisk() const override { return file_->Size(); }
122+
121123
const string& filename() const override {
122124
return file_->filename();
123125
}
@@ -173,9 +175,8 @@ class RWFileImpl : public RWFile {
173175
return Status::OK();
174176
}
175177

176-
Status Size(uint64_t* size) const override {
177-
*size = file_->Size();
178-
return Status::OK();
178+
Result<uint64_t> Size() const override {
179+
return file_->Size();
179180
}
180181

181182
const string& filename() const override {

0 commit comments

Comments
 (0)