1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
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 #define LOG_TAG "RdbSqlStatistic"
17 
18 #include "rdb_sql_statistic.h"
19 
20 #include <thread>
21 
22 #include "concurrent_map.h"
23 #include "logger.h"
24 #include "rdb_errno.h"
25 #include "rdb_platform.h"
26 #include "task_executor.h"
27 namespace OHOS::DistributedRdb {
28 using namespace OHOS::Rdb;
29 using namespace OHOS::NativeRdb;
30 ConcurrentMap<SqlObserver *, std::shared_ptr<SqlObserver>> SqlStatistic::observers_;
31 ConcurrentMap<uint64_t, std::shared_ptr<SqlObserver::SqlExecutionInfo>> SqlStatistic::execInfos_;
32 bool SqlStatistic::enabled_ = false;
33 std::atomic_uint32_t SqlStatistic::seqId_ = 0;
Subscribe(std::shared_ptr<SqlObserver> observer)34 int SqlStatistic::Subscribe(std::shared_ptr<SqlObserver> observer)
35 {
36     observers_.ComputeIfAbsent(observer.get(), [observer](auto &) {
37         enabled_ = true;
38         return observer;
39     });
40     return E_OK;
41 }
42 
Unsubscribe(std::shared_ptr<SqlObserver> observer)43 int SqlStatistic::Unsubscribe(std::shared_ptr<SqlObserver> observer)
44 {
45     observers_.Erase(observer.get());
46     observers_.DoActionIfEmpty([]() {
47         enabled_ = false;
48         execInfos_.Clear();
49     });
50     return E_OK;
51 }
52 
GenerateId()53 uint32_t SqlStatistic::GenerateId()
54 {
55     return ++seqId_;
56 }
57 
SqlStatistic(const std::string & sql,int32_t step,uint32_t seqId)58 SqlStatistic::SqlStatistic(const std::string &sql, int32_t step, uint32_t seqId)
59 {
60     if (!enabled_) {
61         return;
62     }
63     step_ = step;
64     key_ = seqId == 0 ? GetThreadId() : uint64_t(seqId);
65     time_ = std::chrono::steady_clock::now();
66     auto it = execInfos_.Find(key_);
67     if (it.first) {
68         execInfo_ = it.second;
69     }
70 
71     if (execInfo_ == nullptr && seqId != 0) {
72         it = execInfos_.Find(GetThreadId());
73         execInfo_ = it.second;
74     }
75 
76     if (execInfo_ == nullptr) {
77         execInfo_ = std::shared_ptr<SqlExecInfo>(new (std::nothrow) SqlExecInfo(), Release);
78         execInfos_.Insert(key_, execInfo_);
79     }
80 
81     if (step_ == STEP_PREPARE && !sql.empty()) {
82         execInfo_->sql_.emplace_back(sql);
83     }
84 }
85 
~SqlStatistic()86 SqlStatistic::~SqlStatistic()
87 {
88     if (!enabled_) {
89         return;
90     }
91     if (execInfo_ == nullptr) {
92         return;
93     }
94     auto interval = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - time_);
95     switch (step_) {
96         case STEP_WAIT:
97             execInfo_->waitTime_ += interval.count();
98             break;
99         case STEP_PREPARE:
100             execInfo_->prepareTime_ += interval.count();
101             break;
102         case STEP_EXECUTE:
103             execInfo_->executeTime_ += interval.count();
104             break;
105         case STEP_TOTAL:
106         case STEP_TOTAL_RES:
107             execInfo_->totalTime_ += interval.count();
108             execInfos_.Erase(key_);
109             break;
110         default:
111             execInfo_->totalTime_ += interval.count();
112             break;
113     }
114 }
115 
Release(SqlExecInfo * execInfo)116 void SqlStatistic::Release(SqlExecInfo *execInfo)
117 {
118     if (execInfo == nullptr) {
119         return;
120     }
121     if (execInfo->sql_.empty()) {
122         delete execInfo;
123         return;
124     }
125     auto executor = TaskExecutor::GetInstance().GetExecutor();
126     if (executor == nullptr) {
127         delete execInfo;
128         return;
129     }
130     executor->Execute([info = std::move(*execInfo)]() {
131         observers_.ForEachCopies([&info](auto key, std::shared_ptr<SqlObserver> &observer) {
132             if (observer == nullptr) {
133                 return false;
134             }
135             observer->OnStatistic(info);
136             return false;
137         });
138     });
139     delete execInfo;
140 }
141 }