@@ -1036,37 +1036,86 @@ timeline_source::rebuild_indexes()
10361036 this ->ts_index_progress (std::nullopt );
10371037 }
10381038
1039+ std::set<string_fragment> consumed_tag_keys;
10391040 {
1040- static const auto START_RE = lnav::pcre2pp::code::from_const (
1041- R"( ^(?:start(?:ed)?|begin)|\b(?:start(?:ed)?|begin)$)" ,
1041+ static const auto START_PREFIX_RE = lnav::pcre2pp::code::from_const (
1042+ R"( ^#(?:start(?:ed)?|begin)[-_:.]?(.*)$)" , PCRE2_CASELESS );
1043+ static const auto START_SUFFIX_RE = lnav::pcre2pp::code::from_const (
1044+ R"( ^(.*?)(?:[-_:.])?\b(?:start(?:ed)?|begin)$)" , PCRE2_CASELESS );
1045+ static const auto STOP_PREFIX_RE = lnav::pcre2pp::code::from_const (
1046+ R"( ^#(?:stop(?:ped)?|end(?:ed)?|finish(?:ed)?)[-_:.]?(.*)$)" ,
1047+ PCRE2_CASELESS );
1048+ static const auto STOP_SUFFIX_RE = lnav::pcre2pp::code::from_const (
1049+ R"( ^(.*?)(?:[-_:.])?\b(?:stop(?:ped)?|end(?:ed)?|finish(?:ed)?)$)" ,
10421050 PCRE2_CASELESS );
10431051
1044- std::vector<opid_row*> start_tags;
1052+ struct span_event {
1053+ bool se_is_start;
1054+ std::chrono::microseconds se_time;
1055+ opid_row* se_row;
1056+ string_fragment se_key;
1057+ };
1058+ std::map<string_fragment, std::vector<span_event>> events_by_base;
1059+ thread_local auto md = lnav::pcre2pp::match_data::unitialized ();
10451060 for (auto & pair : this ->ts_active_opids ) {
10461061 if (pair.second .or_type != row_type::tag) {
10471062 continue ;
10481063 }
1049- if (START_RE .find_in (pair.second .or_name ).ignore_error ()) {
1050- start_tags.emplace_back (&pair.second );
1064+ auto tag = pair.second .or_name ;
1065+ std::optional<bool > is_start;
1066+ std::optional<string_fragment> base;
1067+ if (START_PREFIX_RE .capture_from (tag).into (md).found_p ()) {
1068+ is_start = true ;
1069+ base = md[1 ];
1070+ } else if (START_SUFFIX_RE .capture_from (tag).into (md).found_p ()) {
1071+ is_start = true ;
1072+ base = md[1 ];
1073+ } else if (STOP_PREFIX_RE .capture_from (tag).into (md).found_p ()) {
1074+ is_start = false ;
1075+ base = md[1 ];
1076+ } else if (STOP_SUFFIX_RE .capture_from (tag).into (md).found_p ()) {
1077+ is_start = false ;
1078+ base = md[1 ];
10511079 }
1080+ if (!is_start.has_value ()) {
1081+ continue ;
1082+ }
1083+ if (base->empty ()) {
1084+ continue ;
1085+ }
1086+ events_by_base[base.value ()].push_back ({
1087+ is_start.value (),
1088+ pair.second .or_value .otr_range .tr_begin ,
1089+ &pair.second ,
1090+ pair.first ,
1091+ });
10521092 }
1053- std::stable_sort (start_tags.begin (),
1054- start_tags.end (),
1055- [](const auto * lhs, const auto * rhs) {
1056- if (lhs->or_name == rhs->or_name ) {
1057- return lhs->or_value .otr_range .tr_begin
1058- < rhs->or_value .otr_range .tr_begin ;
1059- }
1060- return lhs->or_name < rhs->or_name ;
1061- });
1062- for (size_t i = 0 ; i < start_tags.size (); i++) {
1063- if (i + 1 < start_tags.size ()
1064- && start_tags[i]->or_name == start_tags[i + 1 ]->or_name )
1065- {
1066- start_tags[i]->or_value .otr_range .tr_end
1067- = start_tags[i + 1 ]->or_value .otr_range .tr_begin - 1us;
1068- } else {
1069- start_tags[i]->or_value .otr_range .tr_end = last_log_time;
1093+
1094+ for (auto & base_pair : events_by_base) {
1095+ auto & events = base_pair.second ;
1096+ std::stable_sort (
1097+ events.begin (), events.end (), [](const auto & l, const auto & r) {
1098+ if (l.se_time != r.se_time ) {
1099+ return l.se_time < r.se_time ;
1100+ }
1101+ return l.se_is_start && !r.se_is_start ;
1102+ });
1103+ opid_row* current_start = nullptr ;
1104+ for (const auto & evt : events) {
1105+ if (evt.se_is_start ) {
1106+ if (current_start != nullptr ) {
1107+ current_start->or_value .otr_range .tr_end
1108+ = evt.se_time - 1us;
1109+ }
1110+ current_start = evt.se_row ;
1111+ } else if (current_start != nullptr ) {
1112+ current_start->or_value .otr_range .tr_end = evt.se_time ;
1113+ consumed_tag_keys.insert (evt.se_key );
1114+ current_start = nullptr ;
1115+ }
1116+ }
1117+ if (current_start != nullptr ) {
1118+ current_start->or_value .otr_range .tr_end = last_log_time;
10701119 }
10711120 }
10721121 }
@@ -1080,10 +1129,10 @@ timeline_source::rebuild_indexes()
10801129 next_iter = std::next (next_iter);
10811130 }
10821131
1083- auto part_key = fmt::format (
1084- FMT_STRING (" {}@{}" ), part_name, begin_time.count ());
1085- auto part_key_sf = string_fragment::from_str (part_key). to_owned (
1086- this ->ts_allocator );
1132+ auto part_key
1133+ = fmt::format ( FMT_STRING (" {}@{}" ), part_name, begin_time.count ());
1134+ auto part_key_sf
1135+ = string_fragment::from_str (part_key). to_owned ( this ->ts_allocator );
10871136 auto part_name_sf
10881137 = string_fragment::from_str (part_name).to_owned (this ->ts_allocator );
10891138 auto part_otr = opid_time_range{};
@@ -1120,6 +1169,9 @@ timeline_source::rebuild_indexes()
11201169 this ->ts_time_order .clear ();
11211170 this ->ts_time_order .reserve (this ->ts_active_opids .size ());
11221171 for (auto & pair : this ->ts_active_opids ) {
1172+ if (consumed_tag_keys.count (pair.first ) > 0 ) {
1173+ continue ;
1174+ }
11231175 opid_row& row = pair.second ;
11241176 opid_time_range& otr = pair.second .or_value ;
11251177 std::string full_desc;
0 commit comments