@@ -41,6 +41,7 @@ using namespace facade;
4141
4242using absl::AsciiStrToUpper;
4343using absl::GetFlag;
44+ using absl::StrCat;
4445using absl::StrSplit;
4546
4647namespace {
@@ -128,16 +129,56 @@ constexpr int32_t kLatencyHistogramPrecision = 2;
128129
129130} // namespace
130131
132+ void CommandContext::RecordLatency (facade::ArgSlice tail_args) const {
133+ DCHECK_GT (start_time_ns, 0u );
134+ int64_t after = absl::GetCurrentTimeNanos ();
135+
136+ ServerState* ss = ServerState::tlocal (); // Might have migrated thread, read after invocation
137+ int64_t execution_time_usec = (after - start_time_ns) / 1000 ;
138+
139+ cid->RecordLatency (ss->thread_index (), execution_time_usec);
140+
141+ DCHECK (conn_cntx != nullptr );
142+
143+ // TODO: we should probably discard more commands here,
144+ // not just the blocking ones
145+ const auto * conn = conn_cntx->conn ();
146+ if (conn_cntx->conn_state .squashing_info ) {
147+ // We run from the squashed transaction.
148+ conn = conn_cntx->conn_state .squashing_info ->owner ->conn ();
149+ }
150+
151+ if (!(cid->opt_mask () & CO::BLOCKING) && conn != nullptr &&
152+ // Use SafeTLocal() to avoid accessing the wrong thread local instance
153+ ServerState::SafeTLocal ()->ShouldLogSlowCmd (execution_time_usec)) {
154+ vector<string> aux_params;
155+ CmdArgVec aux_slices;
156+
157+ if (tail_args.empty () && cid->name () == " EXEC" ) {
158+ // abuse tail_args to pass more information about the slow EXEC.
159+ aux_params.emplace_back (StrCat (" CMDCOUNT/" , exec_body_len));
160+ aux_slices.emplace_back (aux_params.back ());
161+ tail_args = absl::MakeSpan (aux_slices);
162+ }
163+ ServerState::SafeTLocal ()->GetSlowLog ().Add (cid->name (), tail_args, conn->GetName (),
164+ conn->RemoteEndpointStr (), execution_time_usec,
165+ absl::GetCurrentTimeNanos () / 1000 );
166+ }
167+ }
168+
131169CommandId::CommandId (const char * name, uint32_t mask, int8_t arity, int8_t first_key,
132170 int8_t last_key, std::optional<uint32_t > acl_categories)
133171 : facade::CommandId(name, ImplicitCategories(mask), arity, first_key, last_key,
134172 acl_categories.value_or(ImplicitAclCategories(mask))) {
135173 implicit_acl_ = !acl_categories.has_value ();
136- hdr_histogram* hist = nullptr ;
137- const int init_result = hdr_init (kLatencyHistogramMinValue , kLatencyHistogramMaxValue ,
138- kLatencyHistogramPrecision , &hist);
139- CHECK_EQ (init_result, 0 ) << " failed to initialize histogram for command " << name;
140- latency_histogram_ = hist;
174+ bool is_latency_tracked = GetFlag (FLAGS_latency_tracking);
175+ if (is_latency_tracked) {
176+ hdr_histogram* hist = nullptr ;
177+ const int init_result = hdr_init (kLatencyHistogramMinValue , kLatencyHistogramMaxValue ,
178+ kLatencyHistogramPrecision , &hist);
179+ CHECK_EQ (init_result, 0 ) << " failed to initialize histogram for command " << name;
180+ latency_histogram_ = hist;
181+ }
141182
142183 if (name_.rfind (" EVAL" , 0 ) == 0 )
143184 kind_multi_ctr_ = CO::MultiControlKind::EVAL;
@@ -149,6 +190,7 @@ CommandId::CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first
149190 kind_pubsub_ = CO::PubSubKind::PATTERN;
150191 else if (base::_in (name_, {" SPUBLISH" , " SSUBSCRIBE" , " SUNSUBSCRIBE" }))
151192 kind_pubsub_ = CO::PubSubKind::SHARDED;
193+ can_be_monitored_ = (opt_mask_ & CO::ADMIN) == 0 && name_ != " EXEC" ;
152194}
153195
154196CommandId::~CommandId () {
@@ -169,8 +211,10 @@ CommandId CommandId::Clone(const std::string_view name) const {
169211
170212 // explicit sharing of the object since it's an alias we can do that.
171213 // I am assuming that the source object lifetime is at least as of the cloned object.
172- hdr_close (cloned.latency_histogram_ ); // Free the histogram in the cloned object.
173- cloned.latency_histogram_ = static_cast <hdr_histogram*>(latency_histogram_);
214+ if (cloned.latency_histogram_ ) {
215+ hdr_close (cloned.latency_histogram_ ); // Free the histogram in the cloned object.
216+ cloned.latency_histogram_ = static_cast <hdr_histogram*>(latency_histogram_);
217+ }
174218 return cloned;
175219}
176220
@@ -189,28 +233,6 @@ bool CommandId::IsMultiTransactional() const {
189233 return kind_multi_ctr_.has_value ();
190234}
191235
192- uint64_t CommandId::Invoke (CmdArgList args, const CommandContext& cmd_cntx) const {
193- uint64_t before = cmd_cntx.conn_cntx ->conn_state .cmd_start_time_ns ;
194- DCHECK_GT (before, 0u );
195- handler_ (args, cmd_cntx);
196- int64_t after = absl::GetCurrentTimeNanos ();
197-
198- ServerState* ss = ServerState::tlocal (); // Might have migrated thread, read after invocation
199- int64_t execution_time_usec = (after - before) / 1000 ;
200-
201- auto & ent = command_stats_[ss->thread_index ()];
202-
203- ++ent.first ;
204- ent.second += execution_time_usec;
205- static const bool is_latency_tracked = GetFlag (FLAGS_latency_tracking);
206- if (is_latency_tracked) {
207- if (hdr_histogram* cmd_histogram = latency_histogram_; cmd_histogram != nullptr ) {
208- hdr_record_value (cmd_histogram, execution_time_usec);
209- }
210- }
211- return execution_time_usec;
212- }
213-
214236optional<facade::ErrorReply> CommandId::Validate (CmdArgList tail_args) const {
215237 if ((arity () > 0 && tail_args.size () + 1 != size_t (arity ())) ||
216238 (arity () < 0 && tail_args.size () + 1 < size_t (-arity ()))) {
@@ -238,8 +260,15 @@ void CommandId::ResetStats(unsigned thread_index) {
238260 }
239261}
240262
241- hdr_histogram* CommandId::LatencyHist () const {
242- return latency_histogram_;
263+ void CommandId::RecordLatency (unsigned tid, uint64_t latency_usec) const {
264+ auto & ent = command_stats_[tid];
265+
266+ ++ent.first ;
267+ ent.second += latency_usec;
268+
269+ if (latency_histogram_) {
270+ hdr_record_value (latency_histogram_, latency_usec);
271+ }
243272}
244273
245274CommandRegistry::CommandRegistry () {
@@ -280,7 +309,7 @@ CommandRegistry& CommandRegistry::operator<<(CommandId cmd) {
280309 if (it->second .empty ()) {
281310 return *this ; // Incase of empty string we want to remove the command from registry.
282311 }
283- k = is_sub_command ? absl:: StrCat (it->second , " " , maybe_subcommand[1 ]) : it->second ;
312+ k = is_sub_command ? StrCat (it->second , " " , maybe_subcommand[1 ]) : it->second ;
284313 }
285314
286315 if (restricted_cmds_.find (k) != restricted_cmds_.end ()) {
@@ -333,7 +362,7 @@ std::pair<const CommandId*, ParsedArgs> CommandRegistry::FindExtended(string_vie
333362 }
334363
335364 auto second_cmd = absl::AsciiStrToUpper (tail_args.Front ());
336- string full_cmd = absl:: StrCat (cmd, " " , second_cmd);
365+ string full_cmd = StrCat (cmd, " " , second_cmd);
337366
338367 return {Find (full_cmd), tail_args.Tail ()};
339368 }
@@ -355,7 +384,7 @@ absl::flat_hash_map<std::string, hdr_histogram*> CommandRegistry::LatencyMap() c
355384 absl::flat_hash_map<std::string, hdr_histogram*> cmd_latencies;
356385 cmd_latencies.reserve (cmd_map_.size ());
357386 for (const auto & [cmd_name, cmd] : cmd_map_) {
358- cmd_latencies.insert ({absl::AsciiStrToLower (cmd_name), cmd.LatencyHist ()});
387+ cmd_latencies.insert ({absl::AsciiStrToLower (cmd_name), cmd.GetLatencyHist ()});
359388 }
360389 return cmd_latencies;
361390}
0 commit comments