diff --git a/BUILD b/BUILD index adea3f67e..1d16011a5 100644 --- a/BUILD +++ b/BUILD @@ -1,4 +1,4 @@ -load("@rules_foreign_cc//tools/build_defs:configure.bzl", "configure_make") +load("@rules_foreign_cc//foreign_cc:configure.bzl", "configure_make") # load("@rules_foreign_cc//tools/build_defs:make.bzl", "make") configure_make( diff --git a/WORKSPACE b/WORKSPACE index 4f41e44fa..3deb6c5e1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -18,11 +18,14 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Rule repository http_archive( name = "rules_foreign_cc", - strip_prefix = "rules_foreign_cc-master", - url = "https://github.com/bazelbuild/rules_foreign_cc/archive/master.zip", + strip_prefix = "rules_foreign_cc-main", + #url = "https://github.com/bazelbuild/rules_foreign_cc/archive/master.zip", + url = "https://github.com/shiyi23/sentinel-cpp/raw/master/rules_foreign_cc-main.zip", ) -load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") +#load("@rules_foreign_cc//:workspace_definitions.bzl", "rules_foreign_cc_dependencies") + +load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") rules_foreign_cc_dependencies() diff --git a/rules_foreign_cc-main.zip b/rules_foreign_cc-main.zip new file mode 100644 index 000000000..073b39917 Binary files /dev/null and b/rules_foreign_cc-main.zip differ diff --git a/sentinel-core/log/block/block_log_task.cc b/sentinel-core/log/block/block_log_task.cc old mode 100644 new mode 100755 index 27192d639..44e2c7cd3 --- a/sentinel-core/log/block/block_log_task.cc +++ b/sentinel-core/log/block/block_log_task.cc @@ -1,15 +1,14 @@ -#include "sentinel-core/log/block/block_log_task.h" +#include "block_log_task.h" #include #include #include -#include "sentinel-core/log/logger.h" -#include "sentinel-core/utils/time_utils.h" - #include "absl/strings/str_format.h" #include "absl/time/time.h" +#include "logger.h" #include "spdlog/sinks/rotating_file_sink.h" +#include "statistic_time_utils.h" using namespace Sentinel::Utils; diff --git a/sentinel-core/statistic/base/BUILD b/sentinel-core/statistic/base/BUILD index c8a5a837e..cb636f354 100644 --- a/sentinel-core/statistic/base/BUILD +++ b/sentinel-core/statistic/base/BUILD @@ -75,11 +75,14 @@ cc_library( name = "leap_array_lib", srcs = [ "leap_array.h", + "statistic_time_utils.h", + "statistic_time_utils.cc", ], copts = DEFAULT_COPTS, deps = [ ":window_wrap_lib", - "//sentinel-core/log:logger_lib", + #"//sentinel-core/utils:utils_lib" + #"//sentinel-core/log:logger_lib", ] ) diff --git a/sentinel-core/statistic/base/bucket_leap_array.cc b/sentinel-core/statistic/base/bucket_leap_array.cc old mode 100644 new mode 100755 index 0eb7e1e29..220faab51 --- a/sentinel-core/statistic/base/bucket_leap_array.cc +++ b/sentinel-core/statistic/base/bucket_leap_array.cc @@ -1,4 +1,4 @@ -#include "sentinel-core/statistic/base/bucket_leap_array.h" +#include "bucket_leap_array.h" namespace Sentinel { namespace Stat { diff --git a/sentinel-core/statistic/base/bucket_leap_array.h b/sentinel-core/statistic/base/bucket_leap_array.h index 54ace566f..e8a4f5154 100644 --- a/sentinel-core/statistic/base/bucket_leap_array.h +++ b/sentinel-core/statistic/base/bucket_leap_array.h @@ -2,8 +2,8 @@ #include -#include "sentinel-core/statistic/base/leap_array.h" -#include "sentinel-core/statistic/base/metric_bucket.h" +#include "leap_array.h" +#include "metric_bucket.h" namespace Sentinel { namespace Stat { diff --git a/sentinel-core/statistic/base/leap_array.h b/sentinel-core/statistic/base/leap_array.h old mode 100644 new mode 100755 index 7a43f1c1e..2fe0a1b82 --- a/sentinel-core/statistic/base/leap_array.h +++ b/sentinel-core/statistic/base/leap_array.h @@ -5,9 +5,8 @@ #include #include -#include "sentinel-core/log/logger.h" -#include "sentinel-core/statistic/base/window_wrap.h" -#include "sentinel-core/utils/time_utils.h" +#include "statistic_time_utils.h" +#include "window_wrap.h" namespace Sentinel { namespace Stat { @@ -66,7 +65,7 @@ int32_t LeapArray::IntervalInMs() const { template WindowWrapSharedPtr LeapArray::CurrentWindow() { - return this->CurrentWindow(Utils::TimeUtils::CurrentTimeMillis().count()); + return this->CurrentWindow(Statistic_Utils::TimeUtils::CurrentTimeMillis().count()); } template @@ -119,7 +118,7 @@ int64_t LeapArray::CalculateWindowStart(int64_t time_millis) const { template bool LeapArray::IsBucketDeprecated( const WindowWrapSharedPtr& wrap) const { - return this->IsBucketDeprecated(Utils::TimeUtils::CurrentTimeMillis().count(), + return this->IsBucketDeprecated(Statistic_Utils::TimeUtils::CurrentTimeMillis().count(), wrap); } @@ -131,12 +130,12 @@ bool LeapArray::IsBucketDeprecated( template std::vector> LeapArray::Buckets() const { - return this->Buckets(Utils::TimeUtils::CurrentTimeMillis().count()); + return this->Buckets(Statistic_Utils::TimeUtils::CurrentTimeMillis().count()); } template std::vector> LeapArray::Values() const { - return this->Values(Utils::TimeUtils::CurrentTimeMillis().count()); + return this->Values(Statistic_Utils::TimeUtils::CurrentTimeMillis().count()); } template diff --git a/sentinel-core/statistic/base/metric_bucket.h b/sentinel-core/statistic/base/metric_bucket.h old mode 100644 new mode 100755 index e7f94ba4d..c01916b0a --- a/sentinel-core/statistic/base/metric_bucket.h +++ b/sentinel-core/statistic/base/metric_bucket.h @@ -4,7 +4,7 @@ #include #include "sentinel-core/common/constants.h" -#include "sentinel-core/statistic/base/metric_event.h" +#include "metric_event.h" namespace Sentinel { namespace Stat { @@ -19,11 +19,16 @@ class MetricBucket { void Add(const MetricEvent& event, int64_t n); void AddRt(int64_t rt); + inline long get_writes() { return writes_.load();}; + inline long get_reads() { return reads_.load();}; + private: const std::unique_ptr[]> counters_ = std::make_unique[]>( static_cast(MetricEvent::Count)); long min_rt_; + std::atomic writes_; + std::atomic reads_; void InitMinRt(); }; diff --git a/sentinel-core/statistic/base/statistic_time_utils.cc b/sentinel-core/statistic/base/statistic_time_utils.cc new file mode 100755 index 000000000..f50307eef --- /dev/null +++ b/sentinel-core/statistic/base/statistic_time_utils.cc @@ -0,0 +1,12 @@ +#include "statistic_time_utils.h" + +namespace Sentinel { +namespace Statistic_Utils { + +std::chrono::milliseconds TimeUtils::CurrentTimeMillis() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); +} + +} // namespace Utils +} // namespace Sentinel \ No newline at end of file diff --git a/sentinel-core/statistic/base/statistic_time_utils.h b/sentinel-core/statistic/base/statistic_time_utils.h new file mode 100755 index 000000000..02e0390e4 --- /dev/null +++ b/sentinel-core/statistic/base/statistic_time_utils.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace Sentinel { +namespace Statistic_Utils { + +class TimeUtils { + public: + TimeUtils() = delete; + + static std::chrono::milliseconds CurrentTimeMillis(); +}; + +} // namespace Utils +} // namespace Sentinel \ No newline at end of file diff --git a/sentinel-core/statistic/base/window_wrap.h b/sentinel-core/statistic/base/window_wrap.h index cf98af0dd..3c0de3e42 100644 --- a/sentinel-core/statistic/base/window_wrap.h +++ b/sentinel-core/statistic/base/window_wrap.h @@ -17,7 +17,10 @@ class WindowWrap { int64_t BucketStart() const; std::shared_ptr Value() const; - void ResetTo(int64_t start_time); + inline void ResetTo(int64_t start_time) + { + bucket_start_ = start_time; + } bool IsTimeInBucket(int64_t time_millis) const; private: @@ -44,12 +47,18 @@ std::shared_ptr WindowWrap::Value() const { return value_; } -template -void WindowWrap::ResetTo(int64_t start_time) { - this->bucket_start_ = start_time; -} +//template +//void WindowWrap::ResetTo(int64_t start_time) { +// this->bucket_start_ = start_time; +//} template +/** + * Check whether given timestamp is in current bucket. + * + * @param time_millis valid timestamp in ms + * @return true if the given time is in current bucket, otherwise false + * */ bool WindowWrap::IsTimeInBucket(int64_t time_millis) const { return bucket_start_ <= time_millis && time_millis < bucket_start_ + bucket_length_ms_; diff --git a/sentinel-core/statistic/node/statistic_node.cc b/sentinel-core/statistic/node/statistic_node.cc index 3e1c1d472..9c3f6335f 100644 --- a/sentinel-core/statistic/node/statistic_node.cc +++ b/sentinel-core/statistic/node/statistic_node.cc @@ -81,7 +81,8 @@ bool StatisticNode::IsNodeInTime(const MetricItemSharedPtr& item, } std::unordered_map StatisticNode::Metrics() { - int64_t cur_time = Utils::TimeUtils::CurrentTimeMillis().count(); + using Sentinel::Statistic_Utils; + int64_t cur_time = Sentinel::Statistic_Utils::TimeUtils::CurrentTimeMillis().count(); cur_time = cur_time - cur_time % 1000; std::unordered_map map; std::vector items_of_second = diff --git a/sentinel-core/transport/command/handler/vo/statistic_node_vo.cc b/sentinel-core/transport/command/handler/vo/statistic_node_vo.cc index b3b105816..036831b28 100644 --- a/sentinel-core/transport/command/handler/vo/statistic_node_vo.cc +++ b/sentinel-core/transport/command/handler/vo/statistic_node_vo.cc @@ -24,7 +24,7 @@ std::shared_ptr StatisticNodeVO::FromResourceNode( vo->set_block_per_min(node->BlockCountInMinute()); vo->set_total_per_min(node->TotalCountInMinute()); vo->set_exception_per_min(node->ExceptionCountInMinute()); - vo->set_timestamp(Utils::TimeUtils::CurrentTimeMillis().count()); + vo->set_timestamp(Sentinel::Statistic_Utils::TimeUtils::CurrentTimeMillis().count()); return vo; } diff --git a/sentinel-core/utils/BUILD b/sentinel-core/utils/BUILD index 8ad1e617e..7070792fd 100644 --- a/sentinel-core/utils/BUILD +++ b/sentinel-core/utils/BUILD @@ -11,6 +11,12 @@ cc_library( "time_utils.cc", ], copts = DEFAULT_COPTS, + deps = [ + "//sentinel-core/statistic/base:leap_array_lib", + "//sentinel-core/statistic/base:bucket_leap_array_lib", + "//sentinel-core/statistic/base:metric_bucket_lib", + "//sentinel-core/statistic/base:window_wrap_lib", + ] ) diff --git a/sentinel-core/utils/time_utils.cc b/sentinel-core/utils/time_utils.cc old mode 100644 new mode 100755 index 747a5542b..8e91e63f7 --- a/sentinel-core/utils/time_utils.cc +++ b/sentinel-core/utils/time_utils.cc @@ -1,4 +1,21 @@ -#include "sentinel-core/utils/time_utils.h" +#include "time_utils.h" + +#include + +/** + *

Provides millisecond-level time of OS.

+ *

+ * Here we should see that not all the time TimeUtil should + * keep looping 1_000 times every second (Actually about 800/s due to some losses). + *

+ * * In idle conditions it just acts as System.currentTimeMillis();
+ * * In busy conditions (significantly more than 1_000/s) it keeps loop to reduce costs.
+ * 
+ * For detail design and proposals please goto + * https://github.com/alibaba/Sentinel/issues/1702 + * @author alibaba.com + * @author huangshiyi + * */ namespace Sentinel { namespace Utils { @@ -8,5 +25,123 @@ std::chrono::milliseconds TimeUtils::CurrentTimeMillis() { std::chrono::system_clock::now().time_since_epoch()); } +TimeUtils::TimeUtils() +{ +// statistics_ = new Stat::BucketLeapArray(3, 3000); + currentTimeMillis_ = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + std::thread t(&TimeUtils::Run, this); + t.detach(); +} + +void TimeUtils::Run() +{ + while(true) + { + this->Check(); + if(this->state_ == STATE::RUNNING) + { + this->currentTimeMillis_ = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + this->statistics_->CurrentWindow(currentTimeMillis_.count())->Value()->get_writes().fetch_add(1); + try { + usleep(1000);//1000 microseconds = 1ms + } catch (std::exception e) + { + throw e.what(); + } + continue ; + } + + if(this->state_ == STATE::IDLE) + { + try { + usleep(300000);//300000 micro seconds = 300 ms + } catch (std::exception e) + { + throw e.what(); + } + continue ; + } + + if(this->state_ == STATE::PREPARE) + { + //TODO:should print debug level log info here, but I don't have too much time now + std::cout << "TimeUtils switches to RUNNING" << std::endl; + this->currentTimeMillis_ = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + this->state_ = STATE::RUNNING; + } + + } +} + +void TimeUtils::Check() +{ + std::chrono::milliseconds now = this->CurrentTime(true); + //every period + if(now - this->last_check_ < CHECK_INTERVAL_) + { + return ; + } + this->last_check_ = now; + std::pair qps = this->get_current_qps(now); + if(this->state_ == STATE::IDLE && qps.first > HITS_UPPER_BOUNDARY_) + { + std::cout << "TimeUtil switches to PREPARE for better performance, " + "reads= << " << qps.first << "writes= << " << qps.second << std::endl; + this->state_ = STATE::PREPARE; + } else if(this->state_ == STATE::RUNNING && qps.first < HITS_LOWER_BOUNDARY_) + { + std::cout << "TimeUtil switches to IDLE due to not enough load, " + "reads= " << qps.first << "writes= " << qps.second <state_ = STATE::IDLE; + } +} + +std::pair TimeUtils::get_current_qps(std::chrono::milliseconds now) +{ + auto vec = this->statistics_->Buckets(); + long reads = 0, writes = 0; + int cnt = 0; + for (auto const elem : vec) + { + if (elem->IsTimeInBucket(now.count())) + { + continue ; + } + ++ cnt; + reads += elem->Value()->get_reads().load(); + writes += elem->Value()->get_writes().load(); + if (cnt < 1) + { + return std::make_pair(0,0); + } + } + return std::make_pair(reads/cnt, writes/cnt); +} + +std::chrono::milliseconds TimeUtils::CurrentTime(bool inner_call) +{ + auto now = this->currentTimeMillis_; + auto val = this->statistics_->CurrentWindow()->Value(); + if(!inner_call) + { + //external call + val->get_reads().fetch_add(1); + } + if(this->state_ == STATE::IDLE || this->state_ == STATE::PREPARE) + { + now = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()); + this->currentTimeMillis_ = now; //cache time + if(!inner_call) + { + val->get_writes().fetch_add(1); + } + } + return now; +} + } // namespace Utils } // namespace Sentinel diff --git a/sentinel-core/utils/time_utils.h b/sentinel-core/utils/time_utils.h old mode 100644 new mode 100755 index 8a7a2cbf9..c4b1c38ee --- a/sentinel-core/utils/time_utils.h +++ b/sentinel-core/utils/time_utils.h @@ -1,16 +1,63 @@ -#pragma once +#ifndef TIME_UTILS_H_ +#define TIME_UTILS_H_ #include +#include +#include +#include +#include +#include +//#include "window_wrap.h" +//#include "bucket_leap_array.h" +#include + +//#include "../../bazel-sentinel-cpp/sentinel-core/statistic/base/bucket_leap_array.h" +#include "sentinel-core/statistic/base/bucket_leap_array.h" +#include "sentinel-core/statistic/base/leap_array.h" +#include "sentinel-core/statistic/base/window_wrap.h" namespace Sentinel { namespace Utils { class TimeUtils { + private: + constexpr static std::chrono::milliseconds CHECK_INTERVAL_ {std::chrono::milliseconds{3000}}; + const static long HITS_LOWER_BOUNDARY_ = 800; + const static long HITS_UPPER_BOUNDARY_ = 1200; + + static std::chrono::milliseconds last_check_; + static TimeUtils INSTANCE_; + std::chrono::milliseconds currentTimeMillis_; + Stat::BucketLeapArray* statistics_ = nullptr; + + private: + void Check(); + std::chrono::milliseconds CurrentTime(bool inner_call); + public: - TimeUtils() = delete; + TimeUtils(); + public: + enum class STATE + { + IDLE, + PREPARE, + RUNNING + }; + private: + static std::atomic state_; + + public: + void Run(); + inline STATE& get_state() { auto item = state_.load(); return item; }; + std::pair get_current_qps(std::chrono::milliseconds now); + inline std::chrono::milliseconds get_time() {return CurrentTime(false); } ; + static TimeUtils& get_instance() { return INSTANCE_; } + inline static std::chrono::milliseconds get_current_time_mills() {return INSTANCE_.get_time();}; static std::chrono::milliseconds CurrentTimeMillis(); }; } // namespace Utils } // namespace Sentinel + +#endif //TIME_UTILS_H_ \ No newline at end of file