1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/common/args_tracker.h"
18 
19 #include <algorithm>
20 
21 namespace perfetto {
22 namespace trace_processor {
23 
ArgsTracker(TraceProcessorContext * context)24 ArgsTracker::ArgsTracker(TraceProcessorContext* context) : context_(context) {}
25 
~ArgsTracker()26 ArgsTracker::~ArgsTracker() {
27   Flush();
28 }
29 
AddArg(Column * arg_set_id,uint32_t row,StringId flat_key,StringId key,Variadic value,UpdatePolicy update_policy)30 void ArgsTracker::AddArg(Column* arg_set_id,
31                          uint32_t row,
32                          StringId flat_key,
33                          StringId key,
34                          Variadic value,
35                          UpdatePolicy update_policy) {
36   args_.emplace_back();
37 
38   auto* rid_arg = &args_.back();
39   rid_arg->column = arg_set_id;
40   rid_arg->row = row;
41   rid_arg->flat_key = flat_key;
42   rid_arg->key = key;
43   rid_arg->value = value;
44   rid_arg->update_policy = update_policy;
45 }
46 
Flush()47 void ArgsTracker::Flush() {
48   using Arg = GlobalArgsTracker::Arg;
49 
50   if (args_.empty())
51     return;
52 
53   // We sort here because a single packet may add multiple args with different
54   // rowids.
55   auto comparator = [](const Arg& f, const Arg& s) {
56     // We only care that all args for a specific arg set appear in a contiguous
57     // block and that args within one arg set are sorted by key, but not about
58     // the relative order of one block to another. The simplest way to achieve
59     // that is to sort by table column pointer & row, which identify the arg
60     // set, and then by key.
61     if (f.column == s.column && f.row == s.row)
62       return f.key < s.key;
63     if (f.column == s.column)
64       return f.row < s.row;
65     return f.column < s.column;
66   };
67   std::stable_sort(args_.begin(), args_.end(), comparator);
68 
69   for (uint32_t i = 0; i < args_.size();) {
70     const auto& arg = args_[i];
71     Column* column = arg.column;
72     auto row = arg.row;
73 
74     uint32_t next_rid_idx = i + 1;
75     while (next_rid_idx < args_.size() &&
76            column == args_[next_rid_idx].column &&
77            row == args_[next_rid_idx].row) {
78       next_rid_idx++;
79     }
80 
81     ArgSetId set_id =
82         context_->global_args_tracker->AddArgSet(args_, i, next_rid_idx);
83     column->Set(row, SqlValue::Long(set_id));
84 
85     i = next_rid_idx;
86   }
87   args_.clear();
88 }
89 
BoundInserter(ArgsTracker * args_tracker,Column * arg_set_id_column,uint32_t row)90 ArgsTracker::BoundInserter::BoundInserter(ArgsTracker* args_tracker,
91                                           Column* arg_set_id_column,
92                                           uint32_t row)
93     : args_tracker_(args_tracker),
94       arg_set_id_column_(arg_set_id_column),
95       row_(row) {}
96 
~BoundInserter()97 ArgsTracker::BoundInserter::~BoundInserter() {}
98 
99 ArgsTracker::BoundInserter::BoundInserter(BoundInserter&&) = default;
100 ArgsTracker::BoundInserter& ArgsTracker::BoundInserter::operator=(
101     BoundInserter&&) = default;
102 
103 }  // namespace trace_processor
104 }  // namespace perfetto
105