Allow copy for PerfContext objects (#4919)

Summary:
Existing implementation of PerfContext does not define copy constructor or assignment operator, which could potentially cause problems when user create copies and resets the builtin one. This PR address the issue by providing these two constructors with deep copy semantics.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/4919

Differential Revision: D13960406

Pulled By: miasantreble

fbshipit-source-id: 36aab5aaee65d4480f537e4e22148faa45e8e334
main
Zhongyi Xie 5 years ago committed by Facebook Github Bot
parent c9a52cbdc8
commit 00ed41daee
  1. 83
      db/perf_context_test.cc
  2. 6
      include/rocksdb/perf_context.h
  3. 284
      monitoring/perf_context.cc

@ -688,6 +688,89 @@ TEST_F(PerfContextTest, MergeOperatorTime) {
delete db;
}
TEST_F(PerfContextTest, CopyAndMove) {
// Assignment operator
{
get_perf_context()->Reset();
get_perf_context()->EnablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5);
ASSERT_EQ(
1,
(*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful);
PerfContext perf_context_assign;
perf_context_assign = *get_perf_context();
ASSERT_EQ(
1,
(*(perf_context_assign.level_to_perf_context))[5].bloom_filter_useful);
get_perf_context()->ClearPerLevelPerfContext();
get_perf_context()->Reset();
ASSERT_EQ(
1,
(*(perf_context_assign.level_to_perf_context))[5].bloom_filter_useful);
perf_context_assign.ClearPerLevelPerfContext();
perf_context_assign.Reset();
}
// Copy constructor
{
get_perf_context()->Reset();
get_perf_context()->EnablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5);
ASSERT_EQ(
1,
(*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful);
PerfContext perf_context_copy(*get_perf_context());
ASSERT_EQ(
1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful);
get_perf_context()->ClearPerLevelPerfContext();
get_perf_context()->Reset();
ASSERT_EQ(
1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful);
perf_context_copy.ClearPerLevelPerfContext();
perf_context_copy.Reset();
}
// Move constructor
{
get_perf_context()->Reset();
get_perf_context()->EnablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5);
ASSERT_EQ(
1,
(*(get_perf_context()->level_to_perf_context))[5].bloom_filter_useful);
PerfContext perf_context_move = std::move(*get_perf_context());
ASSERT_EQ(
1, (*(perf_context_move.level_to_perf_context))[5].bloom_filter_useful);
get_perf_context()->ClearPerLevelPerfContext();
get_perf_context()->Reset();
ASSERT_EQ(
1, (*(perf_context_move.level_to_perf_context))[5].bloom_filter_useful);
perf_context_move.ClearPerLevelPerfContext();
perf_context_move.Reset();
}
}
TEST_F(PerfContextTest, PerfContextDisableEnable) {
get_perf_context()->Reset();
get_perf_context()->EnablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_full_positive, 1, 0);
get_perf_context()->DisablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(bloom_filter_useful, 1, 5);
get_perf_context()->EnablePerLevelPerfContext();
PERF_COUNTER_BY_LEVEL_ADD(block_cache_hit_count, 1, 0);
get_perf_context()->DisablePerLevelPerfContext();
PerfContext perf_context_copy(*get_perf_context());
ASSERT_EQ(1, (*(perf_context_copy.level_to_perf_context))[0]
.bloom_filter_full_positive);
// this was set when per level perf context is disabled, should not be copied
ASSERT_NE(
1, (*(perf_context_copy.level_to_perf_context))[5].bloom_filter_useful);
ASSERT_EQ(
1, (*(perf_context_copy.level_to_perf_context))[0].block_cache_hit_count);
perf_context_copy.ClearPerLevelPerfContext();
perf_context_copy.Reset();
get_perf_context()->ClearPerLevelPerfContext();
get_perf_context()->Reset();
}
TEST_F(PerfContextTest, PerfContextByLevelGetSet) {
get_perf_context()->Reset();
get_perf_context()->EnablePerLevelPerfContext();

@ -45,6 +45,12 @@ struct PerfContext {
~PerfContext();
PerfContext() {}
PerfContext(const PerfContext&);
PerfContext& operator=(const PerfContext&);
PerfContext(PerfContext&&) noexcept;
void Reset(); // reset all performance counters to zero
std::string ToString(bool exclude_zero_counters = false) const;

@ -37,6 +37,285 @@ PerfContext::~PerfContext() {
#endif
}
PerfContext::PerfContext(const PerfContext& other) {
#ifndef NPERF_CONTEXT
user_key_comparison_count = other.user_key_comparison_count;
block_cache_hit_count = other.block_cache_hit_count;
block_read_count = other.block_read_count;
block_read_byte = other.block_read_byte;
block_read_time = other.block_read_time;
block_cache_index_hit_count = other.block_cache_index_hit_count;
index_block_read_count = other.index_block_read_count;
block_cache_filter_hit_count = other.block_cache_filter_hit_count;
filter_block_read_count = other.filter_block_read_count;
compression_dict_block_read_count = other.compression_dict_block_read_count;
block_checksum_time = other.block_checksum_time;
block_decompress_time = other.block_decompress_time;
get_read_bytes = other.get_read_bytes;
multiget_read_bytes = other.multiget_read_bytes;
iter_read_bytes = other.iter_read_bytes;
internal_key_skipped_count = other.internal_key_skipped_count;
internal_delete_skipped_count = other.internal_delete_skipped_count;
internal_recent_skipped_count = other.internal_recent_skipped_count;
internal_merge_count = other.internal_merge_count;
write_wal_time = other.write_wal_time;
get_snapshot_time = other.get_snapshot_time;
get_from_memtable_time = other.get_from_memtable_time;
get_from_memtable_count = other.get_from_memtable_count;
get_post_process_time = other.get_post_process_time;
get_from_output_files_time = other.get_from_output_files_time;
seek_on_memtable_time = other.seek_on_memtable_time;
seek_on_memtable_count = other.seek_on_memtable_count;
next_on_memtable_count = other.next_on_memtable_count;
prev_on_memtable_count = other.prev_on_memtable_count;
seek_child_seek_time = other.seek_child_seek_time;
seek_child_seek_count = other.seek_child_seek_count;
seek_min_heap_time = other.seek_min_heap_time;
seek_internal_seek_time = other.seek_internal_seek_time;
find_next_user_entry_time = other.find_next_user_entry_time;
write_pre_and_post_process_time = other.write_pre_and_post_process_time;
write_memtable_time = other.write_memtable_time;
write_delay_time = other.write_delay_time;
write_thread_wait_nanos = other.write_thread_wait_nanos;
write_scheduling_flushes_compactions_time =
other.write_scheduling_flushes_compactions_time;
db_mutex_lock_nanos = other.db_mutex_lock_nanos;
db_condition_wait_nanos = other.db_condition_wait_nanos;
merge_operator_time_nanos = other.merge_operator_time_nanos;
read_index_block_nanos = other.read_index_block_nanos;
read_filter_block_nanos = other.read_filter_block_nanos;
new_table_block_iter_nanos = other.new_table_block_iter_nanos;
new_table_iterator_nanos = other.new_table_iterator_nanos;
block_seek_nanos = other.block_seek_nanos;
find_table_nanos = other.find_table_nanos;
bloom_memtable_hit_count = other.bloom_memtable_hit_count;
bloom_memtable_miss_count = other.bloom_memtable_miss_count;
bloom_sst_hit_count = other.bloom_sst_hit_count;
bloom_sst_miss_count = other.bloom_sst_miss_count;
key_lock_wait_time = other.key_lock_wait_time;
key_lock_wait_count = other.key_lock_wait_count;
env_new_sequential_file_nanos = other.env_new_sequential_file_nanos;
env_new_random_access_file_nanos = other.env_new_random_access_file_nanos;
env_new_writable_file_nanos = other.env_new_writable_file_nanos;
env_reuse_writable_file_nanos = other.env_reuse_writable_file_nanos;
env_new_random_rw_file_nanos = other.env_new_random_rw_file_nanos;
env_new_directory_nanos = other.env_new_directory_nanos;
env_file_exists_nanos = other.env_file_exists_nanos;
env_get_children_nanos = other.env_get_children_nanos;
env_get_children_file_attributes_nanos =
other.env_get_children_file_attributes_nanos;
env_delete_file_nanos = other.env_delete_file_nanos;
env_create_dir_nanos = other.env_create_dir_nanos;
env_create_dir_if_missing_nanos = other.env_create_dir_if_missing_nanos;
env_delete_dir_nanos = other.env_delete_dir_nanos;
env_get_file_size_nanos = other.env_get_file_size_nanos;
env_get_file_modification_time_nanos =
other.env_get_file_modification_time_nanos;
env_rename_file_nanos = other.env_rename_file_nanos;
env_link_file_nanos = other.env_link_file_nanos;
env_lock_file_nanos = other.env_lock_file_nanos;
env_unlock_file_nanos = other.env_unlock_file_nanos;
env_new_logger_nanos = other.env_new_logger_nanos;
get_cpu_nanos = other.get_cpu_nanos;
if (per_level_perf_context_enabled && level_to_perf_context != nullptr) {
ClearPerLevelPerfContext();
}
if (other.level_to_perf_context != nullptr) {
level_to_perf_context = new std::map<uint32_t, PerfContextByLevel>();
*level_to_perf_context = *other.level_to_perf_context;
}
per_level_perf_context_enabled = other.per_level_perf_context_enabled;
#endif
}
PerfContext::PerfContext(PerfContext&& other) noexcept {
#ifndef NPERF_CONTEXT
user_key_comparison_count = other.user_key_comparison_count;
block_cache_hit_count = other.block_cache_hit_count;
block_read_count = other.block_read_count;
block_read_byte = other.block_read_byte;
block_read_time = other.block_read_time;
block_cache_index_hit_count = other.block_cache_index_hit_count;
index_block_read_count = other.index_block_read_count;
block_cache_filter_hit_count = other.block_cache_filter_hit_count;
filter_block_read_count = other.filter_block_read_count;
compression_dict_block_read_count = other.compression_dict_block_read_count;
block_checksum_time = other.block_checksum_time;
block_decompress_time = other.block_decompress_time;
get_read_bytes = other.get_read_bytes;
multiget_read_bytes = other.multiget_read_bytes;
iter_read_bytes = other.iter_read_bytes;
internal_key_skipped_count = other.internal_key_skipped_count;
internal_delete_skipped_count = other.internal_delete_skipped_count;
internal_recent_skipped_count = other.internal_recent_skipped_count;
internal_merge_count = other.internal_merge_count;
write_wal_time = other.write_wal_time;
get_snapshot_time = other.get_snapshot_time;
get_from_memtable_time = other.get_from_memtable_time;
get_from_memtable_count = other.get_from_memtable_count;
get_post_process_time = other.get_post_process_time;
get_from_output_files_time = other.get_from_output_files_time;
seek_on_memtable_time = other.seek_on_memtable_time;
seek_on_memtable_count = other.seek_on_memtable_count;
next_on_memtable_count = other.next_on_memtable_count;
prev_on_memtable_count = other.prev_on_memtable_count;
seek_child_seek_time = other.seek_child_seek_time;
seek_child_seek_count = other.seek_child_seek_count;
seek_min_heap_time = other.seek_min_heap_time;
seek_internal_seek_time = other.seek_internal_seek_time;
find_next_user_entry_time = other.find_next_user_entry_time;
write_pre_and_post_process_time = other.write_pre_and_post_process_time;
write_memtable_time = other.write_memtable_time;
write_delay_time = other.write_delay_time;
write_thread_wait_nanos = other.write_thread_wait_nanos;
write_scheduling_flushes_compactions_time =
other.write_scheduling_flushes_compactions_time;
db_mutex_lock_nanos = other.db_mutex_lock_nanos;
db_condition_wait_nanos = other.db_condition_wait_nanos;
merge_operator_time_nanos = other.merge_operator_time_nanos;
read_index_block_nanos = other.read_index_block_nanos;
read_filter_block_nanos = other.read_filter_block_nanos;
new_table_block_iter_nanos = other.new_table_block_iter_nanos;
new_table_iterator_nanos = other.new_table_iterator_nanos;
block_seek_nanos = other.block_seek_nanos;
find_table_nanos = other.find_table_nanos;
bloom_memtable_hit_count = other.bloom_memtable_hit_count;
bloom_memtable_miss_count = other.bloom_memtable_miss_count;
bloom_sst_hit_count = other.bloom_sst_hit_count;
bloom_sst_miss_count = other.bloom_sst_miss_count;
key_lock_wait_time = other.key_lock_wait_time;
key_lock_wait_count = other.key_lock_wait_count;
env_new_sequential_file_nanos = other.env_new_sequential_file_nanos;
env_new_random_access_file_nanos = other.env_new_random_access_file_nanos;
env_new_writable_file_nanos = other.env_new_writable_file_nanos;
env_reuse_writable_file_nanos = other.env_reuse_writable_file_nanos;
env_new_random_rw_file_nanos = other.env_new_random_rw_file_nanos;
env_new_directory_nanos = other.env_new_directory_nanos;
env_file_exists_nanos = other.env_file_exists_nanos;
env_get_children_nanos = other.env_get_children_nanos;
env_get_children_file_attributes_nanos =
other.env_get_children_file_attributes_nanos;
env_delete_file_nanos = other.env_delete_file_nanos;
env_create_dir_nanos = other.env_create_dir_nanos;
env_create_dir_if_missing_nanos = other.env_create_dir_if_missing_nanos;
env_delete_dir_nanos = other.env_delete_dir_nanos;
env_get_file_size_nanos = other.env_get_file_size_nanos;
env_get_file_modification_time_nanos =
other.env_get_file_modification_time_nanos;
env_rename_file_nanos = other.env_rename_file_nanos;
env_link_file_nanos = other.env_link_file_nanos;
env_lock_file_nanos = other.env_lock_file_nanos;
env_unlock_file_nanos = other.env_unlock_file_nanos;
env_new_logger_nanos = other.env_new_logger_nanos;
get_cpu_nanos = other.get_cpu_nanos;
if (per_level_perf_context_enabled && level_to_perf_context != nullptr) {
ClearPerLevelPerfContext();
}
if (other.level_to_perf_context != nullptr) {
level_to_perf_context = other.level_to_perf_context;
other.level_to_perf_context = nullptr;
}
per_level_perf_context_enabled = other.per_level_perf_context_enabled;
#endif
}
// TODO(Zhongyi): reduce code duplication between copy constructor and
// assignment operator
PerfContext& PerfContext::operator=(const PerfContext& other) {
#ifndef NPERF_CONTEXT
user_key_comparison_count = other.user_key_comparison_count;
block_cache_hit_count = other.block_cache_hit_count;
block_read_count = other.block_read_count;
block_read_byte = other.block_read_byte;
block_read_time = other.block_read_time;
block_cache_index_hit_count = other.block_cache_index_hit_count;
index_block_read_count = other.index_block_read_count;
block_cache_filter_hit_count = other.block_cache_filter_hit_count;
filter_block_read_count = other.filter_block_read_count;
compression_dict_block_read_count = other.compression_dict_block_read_count;
block_checksum_time = other.block_checksum_time;
block_decompress_time = other.block_decompress_time;
get_read_bytes = other.get_read_bytes;
multiget_read_bytes = other.multiget_read_bytes;
iter_read_bytes = other.iter_read_bytes;
internal_key_skipped_count = other.internal_key_skipped_count;
internal_delete_skipped_count = other.internal_delete_skipped_count;
internal_recent_skipped_count = other.internal_recent_skipped_count;
internal_merge_count = other.internal_merge_count;
write_wal_time = other.write_wal_time;
get_snapshot_time = other.get_snapshot_time;
get_from_memtable_time = other.get_from_memtable_time;
get_from_memtable_count = other.get_from_memtable_count;
get_post_process_time = other.get_post_process_time;
get_from_output_files_time = other.get_from_output_files_time;
seek_on_memtable_time = other.seek_on_memtable_time;
seek_on_memtable_count = other.seek_on_memtable_count;
next_on_memtable_count = other.next_on_memtable_count;
prev_on_memtable_count = other.prev_on_memtable_count;
seek_child_seek_time = other.seek_child_seek_time;
seek_child_seek_count = other.seek_child_seek_count;
seek_min_heap_time = other.seek_min_heap_time;
seek_internal_seek_time = other.seek_internal_seek_time;
find_next_user_entry_time = other.find_next_user_entry_time;
write_pre_and_post_process_time = other.write_pre_and_post_process_time;
write_memtable_time = other.write_memtable_time;
write_delay_time = other.write_delay_time;
write_thread_wait_nanos = other.write_thread_wait_nanos;
write_scheduling_flushes_compactions_time =
other.write_scheduling_flushes_compactions_time;
db_mutex_lock_nanos = other.db_mutex_lock_nanos;
db_condition_wait_nanos = other.db_condition_wait_nanos;
merge_operator_time_nanos = other.merge_operator_time_nanos;
read_index_block_nanos = other.read_index_block_nanos;
read_filter_block_nanos = other.read_filter_block_nanos;
new_table_block_iter_nanos = other.new_table_block_iter_nanos;
new_table_iterator_nanos = other.new_table_iterator_nanos;
block_seek_nanos = other.block_seek_nanos;
find_table_nanos = other.find_table_nanos;
bloom_memtable_hit_count = other.bloom_memtable_hit_count;
bloom_memtable_miss_count = other.bloom_memtable_miss_count;
bloom_sst_hit_count = other.bloom_sst_hit_count;
bloom_sst_miss_count = other.bloom_sst_miss_count;
key_lock_wait_time = other.key_lock_wait_time;
key_lock_wait_count = other.key_lock_wait_count;
env_new_sequential_file_nanos = other.env_new_sequential_file_nanos;
env_new_random_access_file_nanos = other.env_new_random_access_file_nanos;
env_new_writable_file_nanos = other.env_new_writable_file_nanos;
env_reuse_writable_file_nanos = other.env_reuse_writable_file_nanos;
env_new_random_rw_file_nanos = other.env_new_random_rw_file_nanos;
env_new_directory_nanos = other.env_new_directory_nanos;
env_file_exists_nanos = other.env_file_exists_nanos;
env_get_children_nanos = other.env_get_children_nanos;
env_get_children_file_attributes_nanos =
other.env_get_children_file_attributes_nanos;
env_delete_file_nanos = other.env_delete_file_nanos;
env_create_dir_nanos = other.env_create_dir_nanos;
env_create_dir_if_missing_nanos = other.env_create_dir_if_missing_nanos;
env_delete_dir_nanos = other.env_delete_dir_nanos;
env_get_file_size_nanos = other.env_get_file_size_nanos;
env_get_file_modification_time_nanos =
other.env_get_file_modification_time_nanos;
env_rename_file_nanos = other.env_rename_file_nanos;
env_link_file_nanos = other.env_link_file_nanos;
env_lock_file_nanos = other.env_lock_file_nanos;
env_unlock_file_nanos = other.env_unlock_file_nanos;
env_new_logger_nanos = other.env_new_logger_nanos;
get_cpu_nanos = other.get_cpu_nanos;
if (per_level_perf_context_enabled && level_to_perf_context != nullptr) {
ClearPerLevelPerfContext();
}
if (other.level_to_perf_context != nullptr) {
level_to_perf_context = new std::map<uint32_t, PerfContextByLevel>();
*level_to_perf_context = *other.level_to_perf_context;
}
per_level_perf_context_enabled = other.per_level_perf_context_enabled;
#endif
return *this;
}
void PerfContext::Reset() {
#ifndef NPERF_CONTEXT
user_key_comparison_count = 0;
@ -240,7 +519,7 @@ std::string PerfContext::ToString(bool exclude_zero_counters) const {
}
void PerfContext::EnablePerLevelPerfContext() {
if (!level_to_perf_context) {
if (level_to_perf_context == nullptr) {
level_to_perf_context = new std::map<uint32_t, PerfContextByLevel>();
}
per_level_perf_context_enabled = true;
@ -251,7 +530,8 @@ void PerfContext::DisablePerLevelPerfContext(){
}
void PerfContext::ClearPerLevelPerfContext(){
if (level_to_perf_context) {
if (level_to_perf_context != nullptr) {
level_to_perf_context->clear();
delete level_to_perf_context;
level_to_perf_context = nullptr;
}

Loading…
Cancel
Save