1/*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "irq_table.h"
17
18namespace SysTuning {
19namespace TraceStreamer {
20enum class Index : int32_t { ID = 0, TS, DURS, CALL_IDS, CAT, NAME, DEPTH, COOKIE_ID, PARENT_ID, ARGSET, FLAG };
21IrqTable::IrqTable(const TraceDataCache *dataCache) : TableBase(dataCache)
22{
23    tableColumn_.emplace_back(TableBase::ColumnInfo("id", "INTEGER"));
24    tableColumn_.emplace_back(TableBase::ColumnInfo("ts", "INTEGER"));
25    tableColumn_.emplace_back(TableBase::ColumnInfo("dur", "INTEGER"));
26    tableColumn_.emplace_back(TableBase::ColumnInfo("callid", "INTEGER"));
27    tableColumn_.emplace_back(TableBase::ColumnInfo("cat", "TEXT"));
28    tableColumn_.emplace_back(TableBase::ColumnInfo("name", "TEXT"));
29    tableColumn_.emplace_back(TableBase::ColumnInfo("depth", "INTEGER"));
30    tableColumn_.emplace_back(TableBase::ColumnInfo("cookie", "INTEGER"));
31    tableColumn_.emplace_back(TableBase::ColumnInfo("parent_id", "INTEGER"));
32    tableColumn_.emplace_back(TableBase::ColumnInfo("argsetid", "INTEGER"));
33    tableColumn_.emplace_back(TableBase::ColumnInfo("flag", "TEXT"));
34    tablePriKey_.emplace_back("callid");
35    tablePriKey_.emplace_back("ts");
36    tablePriKey_.emplace_back("depth");
37}
38
39IrqTable::~IrqTable() {}
40
41void IrqTable::FilterByConstraint(FilterConstraints &irqfc,
42                                  double &irqfilterCost,
43                                  size_t irqrowCount,
44                                  uint32_t irqcurrenti)
45{
46    // To use the EstimateFilterCost function in the TableBase parent class function to calculate the i-value of each
47    // for loop
48    const auto &irqc = irqfc.GetConstraints()[irqcurrenti];
49    switch (static_cast<Index>(irqc.col)) {
50        case Index::ID: {
51            if (CanFilterId(irqc.op, irqrowCount)) {
52                irqfc.UpdateConstraint(irqcurrenti, true);
53                irqfilterCost += 1; // id can position by 1 step
54            } else {
55                irqfilterCost += irqrowCount; // scan all rows
56            }
57            break;
58        }
59        default:                          // other column
60            irqfilterCost += irqrowCount; // scan all rows
61            break;
62    }
63}
64
65std::unique_ptr<TableBase::Cursor> IrqTable::CreateCursor()
66{
67    return std::make_unique<Cursor>(dataCache_, this);
68}
69
70IrqTable::Cursor::Cursor(const TraceDataCache *dataCache, TableBase *table)
71    : TableBase::Cursor(dataCache, table, static_cast<uint32_t>(dataCache->GetConstIrqData().Size())),
72      slicesObj_(dataCache->GetConstIrqData())
73{
74}
75
76IrqTable::Cursor::~Cursor() {}
77
78int32_t IrqTable::Cursor::Filter(const FilterConstraints &fc, sqlite3_value **argv)
79{
80    // reset indexMap_
81    indexMap_ = std::make_unique<IndexMap>(0, rowCount_);
82
83    if (rowCount_ <= 0) {
84        return SQLITE_OK;
85    }
86
87    auto &irqCs = fc.GetConstraints();
88    for (size_t i = 0; i < irqCs.size(); i++) {
89        const auto &c = irqCs[i];
90        switch (static_cast<Index>(c.col)) {
91            case Index::ID:
92                FilterId(c.op, argv[i]);
93                break;
94            default:
95                break;
96        }
97    }
98
99    auto irqTableOrderbys = fc.GetOrderBys();
100    for (auto i = irqTableOrderbys.size(); i > 0;) {
101        i--;
102        switch (static_cast<Index>(irqTableOrderbys[i].iColumn)) {
103            case Index::ID:
104                indexMap_->SortBy(irqTableOrderbys[i].desc);
105                break;
106            default:
107                break;
108        }
109    }
110
111    return SQLITE_OK;
112}
113
114int32_t IrqTable::Cursor::Column(int32_t column) const
115{
116    switch (static_cast<Index>(column)) {
117        case Index::ID:
118            sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.IdsData()[CurrentRow()]));
119            break;
120        case Index::TS:
121            SetTypeColumnInt64(slicesObj_.TimeStampData()[CurrentRow()], INVALID_UINT64);
122            break;
123        case Index::DURS:
124            SetTypeColumnInt64(slicesObj_.DursData()[CurrentRow()], INVALID_UINT64);
125            break;
126        case Index::CALL_IDS:
127            SetTypeColumnInt64(slicesObj_.CallIds()[CurrentRow()], INVALID_UINT64);
128            break;
129        case Index::CAT: {
130            SetTypeColumnText(slicesObj_.CatsData()[CurrentRow()], INVALID_UINT64);
131            break;
132        }
133        case Index::NAME: {
134            SetTypeColumnText(slicesObj_.NamesData()[CurrentRow()], INVALID_UINT64);
135            break;
136        }
137        case Index::DEPTH:
138            sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.Depths()[CurrentRow()]));
139            break;
140        default:
141            HandleTypeColumns(column);
142    }
143    return SQLITE_OK;
144}
145void IrqTable::Cursor::HandleTypeColumns(int32_t column) const
146{
147    switch (static_cast<Index>(column)) {
148        case Index::COOKIE_ID:
149            SetTypeColumnInt64(slicesObj_.Cookies()[CurrentRow()], INVALID_INT64);
150            break;
151        case Index::PARENT_ID: {
152            if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) {
153                sqlite3_result_int64(context_, static_cast<int64_t>(slicesObj_.ParentIdData()[CurrentRow()].value()));
154            }
155            break;
156        }
157        case Index::ARGSET:
158            SetTypeColumnInt64(slicesObj_.ArgSetIdsData()[CurrentRow()], INVALID_UINT32);
159            break;
160        case Index::FLAG:
161            sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr);
162            break;
163        default:
164            TS_LOGF("Unregistered column : %d", column);
165            break;
166    }
167}
168void IrqTable::GetOrbyes(FilterConstraints &irqfc, EstimatedIndexInfo &irqei)
169{
170    auto irqorderbys = irqfc.GetOrderBys();
171    for (auto i = 0; i < irqorderbys.size(); i++) {
172        switch (static_cast<Index>(irqorderbys[i].iColumn)) {
173            case Index::ID:
174                break;
175            default: // other columns can be sorted by SQLite
176                irqei.isOrdered = false;
177                break;
178        }
179    }
180}
181} // namespace TraceStreamer
182} // namespace SysTuning
183