BufferSlice: stats of total BufferSlices size
GitOrigin-RevId: df712161ba00c4f3d6eae9b6459c69ee046a9bda
This commit is contained in:
parent
f74d8ba023
commit
e75860b2ae
@ -667,7 +667,7 @@ void Binlog::do_reindex() {
|
|||||||
<< fd_size_ << ' ' << detail::file_size(path_) << ' ' << fd_events_ << ' ' << path_;
|
<< fd_size_ << ' ' << detail::file_size(path_) << ' ' << fd_events_ << ' ' << path_;
|
||||||
|
|
||||||
double ratio = static_cast<double>(start_size) / static_cast<double>(finish_size + 1);
|
double ratio = static_cast<double>(start_size) / static_cast<double>(finish_size + 1);
|
||||||
LOG(INFO) << "Regenerate index " << tag("name", path_) << tag("time", format::as_time(finish_time - start_time))
|
LOG(ERROR) << "Regenerate index " << tag("name", path_) << tag("time", format::as_time(finish_time - start_time))
|
||||||
<< tag("before_size", format::as_size(start_size)) << tag("after_size", format::as_size(finish_size))
|
<< tag("before_size", format::as_size(start_size)) << tag("after_size", format::as_size(finish_size))
|
||||||
<< tag("ratio", ratio) << tag("before_events", start_events) << tag("after_events", finish_events);
|
<< tag("ratio", ratio) << tag("before_events", start_events) << tag("after_events", finish_events);
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class ThreadSafeMultiCounter {
|
|||||||
int64 sum(size_t index) const {
|
int64 sum(size_t index) const {
|
||||||
CHECK(index < N);
|
CHECK(index < N);
|
||||||
int64 res = 0;
|
int64 res = 0;
|
||||||
tls_.for_each([&res](auto &value) { res += value[index].load(std::memory_order_relaxed); });
|
tls_.for_each([&res, &index](auto &value) { res += value[index].load(std::memory_order_relaxed); });
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
void clear() {
|
void clear() {
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "td/utils/port/thread_local.h"
|
#include "td/utils/port/thread_local.h"
|
||||||
|
|
||||||
|
#include "td/utils/ThreadSafeCounter.h"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
@ -24,6 +26,16 @@ TD_THREAD_LOCAL BufferAllocator::BufferRawTls *BufferAllocator::buffer_raw_tls;
|
|||||||
|
|
||||||
std::atomic<size_t> BufferAllocator::buffer_mem;
|
std::atomic<size_t> BufferAllocator::buffer_mem;
|
||||||
|
|
||||||
|
static td::ThreadSafeCounter buffer_slice_size_;
|
||||||
|
|
||||||
|
int64 BufferAllocator::get_buffer_slice_size() {
|
||||||
|
return buffer_slice_size_.sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BufferAllocator::track_buffer_slice(int64 size) {
|
||||||
|
buffer_slice_size_.add(size);
|
||||||
|
}
|
||||||
|
|
||||||
size_t BufferAllocator::get_buffer_mem() {
|
size_t BufferAllocator::get_buffer_mem() {
|
||||||
return buffer_mem;
|
return buffer_mem;
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,15 @@ class BufferAllocator {
|
|||||||
static ReaderPtr create_reader(const ReaderPtr &raw);
|
static ReaderPtr create_reader(const ReaderPtr &raw);
|
||||||
|
|
||||||
static size_t get_buffer_mem();
|
static size_t get_buffer_mem();
|
||||||
|
static int64 get_buffer_slice_size();
|
||||||
|
|
||||||
static void clear_thread_local();
|
static void clear_thread_local();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class BufferSlice;
|
||||||
|
|
||||||
|
static void track_buffer_slice(int64 size);
|
||||||
|
|
||||||
static ReaderPtr create_reader_fast(size_t size);
|
static ReaderPtr create_reader_fast(size_t size);
|
||||||
|
|
||||||
static WriterPtr create_writer_exact(size_t size);
|
static WriterPtr create_writer_exact(size_t size);
|
||||||
@ -104,16 +109,29 @@ class BufferSlice {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
begin_ = buffer_->begin_;
|
begin_ = buffer_->begin_;
|
||||||
|
end_ = begin_;
|
||||||
sync_with_writer();
|
sync_with_writer();
|
||||||
}
|
}
|
||||||
BufferSlice(BufferReaderPtr buffer_ptr, size_t begin, size_t end)
|
BufferSlice(BufferReaderPtr buffer_ptr, size_t begin, size_t end)
|
||||||
: buffer_(std::move(buffer_ptr)), begin_(begin), end_(end) {
|
: buffer_(std::move(buffer_ptr)), begin_(begin), end_(end) {
|
||||||
|
debug_track();
|
||||||
|
}
|
||||||
|
BufferSlice(BufferSlice &&other) : BufferSlice(std::move(other.buffer_), other.begin_, other.end_) {
|
||||||
|
debug_untrack(); // yes, debug_untrack
|
||||||
|
}
|
||||||
|
BufferSlice &operator=(BufferSlice &&other) {
|
||||||
|
debug_untrack();
|
||||||
|
buffer_ = std::move(other.buffer_);
|
||||||
|
begin_ = other.begin_;
|
||||||
|
end_ = other.end_;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit BufferSlice(size_t size) : buffer_(BufferAllocator::create_reader(size)) {
|
explicit BufferSlice(size_t size) : buffer_(BufferAllocator::create_reader(size)) {
|
||||||
end_ = buffer_->end_.load(std::memory_order_relaxed);
|
end_ = buffer_->end_.load(std::memory_order_relaxed);
|
||||||
begin_ = end_ - ((size + 7) & -8);
|
begin_ = end_ - ((size + 7) & -8);
|
||||||
end_ = begin_ + size;
|
end_ = begin_ + size;
|
||||||
|
debug_track();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit BufferSlice(Slice slice) : BufferSlice(slice.size()) {
|
explicit BufferSlice(Slice slice) : BufferSlice(slice.size()) {
|
||||||
@ -123,6 +141,17 @@ class BufferSlice {
|
|||||||
BufferSlice(const char *ptr, size_t size) : BufferSlice(Slice(ptr, size)) {
|
BufferSlice(const char *ptr, size_t size) : BufferSlice(Slice(ptr, size)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~BufferSlice() {
|
||||||
|
debug_untrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_track() {
|
||||||
|
BufferAllocator::track_buffer_slice(static_cast<int64>(size()));
|
||||||
|
}
|
||||||
|
void debug_untrack() {
|
||||||
|
BufferAllocator::track_buffer_slice(-static_cast<int64>(size()));
|
||||||
|
}
|
||||||
|
|
||||||
BufferSlice clone() const {
|
BufferSlice clone() const {
|
||||||
if (is_null()) {
|
if (is_null()) {
|
||||||
return BufferSlice(BufferReaderPtr(), begin_, end_);
|
return BufferSlice(BufferReaderPtr(), begin_, end_);
|
||||||
@ -166,14 +195,18 @@ class BufferSlice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool confirm_read(size_t size) {
|
bool confirm_read(size_t size) {
|
||||||
|
debug_untrack();
|
||||||
begin_ += size;
|
begin_ += size;
|
||||||
CHECK(begin_ <= end_);
|
CHECK(begin_ <= end_);
|
||||||
|
debug_track();
|
||||||
return begin_ == end_;
|
return begin_ == end_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void truncate(size_t limit) {
|
void truncate(size_t limit) {
|
||||||
if (size() > limit) {
|
if (size() > limit) {
|
||||||
|
debug_untrack();
|
||||||
end_ = begin_ + limit;
|
end_ = begin_ + limit;
|
||||||
|
debug_track();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +214,7 @@ class BufferSlice {
|
|||||||
auto res = BufferSlice(BufferAllocator::create_reader(buffer_));
|
auto res = BufferSlice(BufferAllocator::create_reader(buffer_));
|
||||||
res.begin_ = static_cast<size_t>(slice.ubegin() - buffer_->data_);
|
res.begin_ = static_cast<size_t>(slice.ubegin() - buffer_->data_);
|
||||||
res.end_ = static_cast<size_t>(slice.uend() - buffer_->data_);
|
res.end_ = static_cast<size_t>(slice.uend() - buffer_->data_);
|
||||||
|
res.debug_track();
|
||||||
CHECK(buffer_->begin_ <= res.begin_);
|
CHECK(buffer_->begin_ <= res.begin_);
|
||||||
CHECK(res.begin_ <= res.end_);
|
CHECK(res.begin_ <= res.end_);
|
||||||
CHECK(res.end_ <= buffer_->end_.load(std::memory_order_relaxed));
|
CHECK(res.end_ <= buffer_->end_.load(std::memory_order_relaxed));
|
||||||
@ -220,9 +254,11 @@ class BufferSlice {
|
|||||||
|
|
||||||
// set end_ into writer's end_
|
// set end_ into writer's end_
|
||||||
size_t sync_with_writer() {
|
size_t sync_with_writer() {
|
||||||
|
debug_untrack();
|
||||||
CHECK(!is_null());
|
CHECK(!is_null());
|
||||||
auto old_end = end_;
|
auto old_end = end_;
|
||||||
end_ = buffer_->end_.load(std::memory_order_acquire);
|
end_ = buffer_->end_.load(std::memory_order_acquire);
|
||||||
|
debug_track();
|
||||||
return end_ - old_end;
|
return end_ - old_end;
|
||||||
}
|
}
|
||||||
bool is_writer_alive() const {
|
bool is_writer_alive() const {
|
||||||
@ -230,6 +266,7 @@ class BufferSlice {
|
|||||||
return buffer_->has_writer_.load(std::memory_order_acquire);
|
return buffer_->has_writer_.load(std::memory_order_acquire);
|
||||||
}
|
}
|
||||||
void clear() {
|
void clear() {
|
||||||
|
debug_untrack();
|
||||||
begin_ = 0;
|
begin_ = 0;
|
||||||
end_ = 0;
|
end_ = 0;
|
||||||
buffer_ = nullptr;
|
buffer_ = nullptr;
|
||||||
|
@ -133,6 +133,7 @@ TEST(Http, reader) {
|
|||||||
clear_thread_locals();
|
clear_thread_locals();
|
||||||
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
SET_VERBOSITY_LEVEL(VERBOSITY_NAME(ERROR));
|
||||||
auto start_mem = BufferAllocator::get_buffer_mem();
|
auto start_mem = BufferAllocator::get_buffer_mem();
|
||||||
|
auto start_size = BufferAllocator::get_buffer_slice_size();
|
||||||
for (int i = 0; i < 20; i++) {
|
for (int i = 0; i < 20; i++) {
|
||||||
td::ChainBufferWriter input_writer;
|
td::ChainBufferWriter input_writer;
|
||||||
auto input = input_writer.extract_reader();
|
auto input = input_writer.extract_reader();
|
||||||
@ -184,6 +185,7 @@ TEST(Http, reader) {
|
|||||||
}
|
}
|
||||||
clear_thread_locals();
|
clear_thread_locals();
|
||||||
ASSERT_EQ(start_mem, BufferAllocator::get_buffer_mem());
|
ASSERT_EQ(start_mem, BufferAllocator::get_buffer_mem());
|
||||||
|
ASSERT_EQ(start_size, BufferAllocator::get_buffer_slice_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Http, gzip_bomb) {
|
TEST(Http, gzip_bomb) {
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include "td/db/binlog/BinlogHelper.h"
|
#include "td/db/binlog/BinlogHelper.h"
|
||||||
#include "td/db/TQueue.h"
|
#include "td/db/TQueue.h"
|
||||||
|
|
||||||
|
#include "td/utils/Random.h"
|
||||||
|
#include "td/utils/buffer.h"
|
||||||
#include "td/utils/int_types.h"
|
#include "td/utils/int_types.h"
|
||||||
#include "td/utils/misc.h"
|
#include "td/utils/misc.h"
|
||||||
#include "td/utils/port/path.h"
|
#include "td/utils/port/path.h"
|
||||||
@ -192,3 +194,35 @@ TEST(TQueue, random) {
|
|||||||
steps.step(rnd);
|
steps.step(rnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TQueue, memory_leak) {
|
||||||
|
//return;
|
||||||
|
auto tqueue = td::TQueue::create();
|
||||||
|
auto tqueue_binlog = td::make_unique<td::TQueueBinlog<td::Binlog>>();
|
||||||
|
std::string binlog_path = "test_tqueue.binlog";
|
||||||
|
td::Binlog::destroy(binlog_path).ensure();
|
||||||
|
auto binlog = std::make_shared<td::Binlog>();
|
||||||
|
binlog->init(binlog_path, [&](const td::BinlogEvent &event) { UNREACHABLE(); }).ensure();
|
||||||
|
tqueue_binlog->set_binlog(std::move(binlog));
|
||||||
|
tqueue->set_callback(std::move(tqueue_binlog));
|
||||||
|
|
||||||
|
double now = 0;
|
||||||
|
std::vector<td::TQueue::EventId> ids;
|
||||||
|
td::Random::Xorshift128plus rnd(123);
|
||||||
|
int i = 0;
|
||||||
|
while (true) {
|
||||||
|
auto id = tqueue->push(1, "a", now + 600000, 0, {}).move_as_ok();
|
||||||
|
ids.push_back(id);
|
||||||
|
if (ids.size() > rnd() % 100000) {
|
||||||
|
auto it = rnd() % ids.size();
|
||||||
|
std::swap(ids.back(), ids[it]);
|
||||||
|
tqueue->forget(1, ids.back());
|
||||||
|
ids.pop_back();
|
||||||
|
}
|
||||||
|
now += 1;
|
||||||
|
if (i++ % 100000 == 0) {
|
||||||
|
LOG(ERROR) << td::BufferAllocator::get_buffer_mem() << " " << tqueue->get_size(1) << " "
|
||||||
|
<< td::BufferAllocator::get_buffer_slice_size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user