xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/module_lifecycle_manager.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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 #ifndef SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_
18 #define SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_
19 
20 #include <memory>
21 #include <string>
22 #include <string_view>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/ext/base/flat_hash_map.h"
26 
27 namespace perfetto::trace_processor::sqlite {
28 
29 // Helper class which abstracts away management of per-vtab state of an SQLite
30 // virtual table module.
31 //
32 // SQLite has some subtle semantics around lifecycle of vtabs which makes state
33 // management complex. This class attempts to encapsulate some of that
34 // complexity as a central place where we can document the quirks.
35 //
36 // Usage of this class:
37 // struct MyModule : sqlite::Module<MyModule> {
38 //   struct Context {
39 //     // Store the manager in the context object.
40 //     ModuleStateManager<MyModule> manager.
41 //     ... (other fields)
42 //   }
43 //   struct Vtab : sqlite::Module<MyModule>::Vtab {
44 //     // Store the per-vtab-state pointer in the vtab object.
45 //     ModuleStateManager<MyModule>::PerVtabState* state;
46 //     ... (other fields)
47 //   }
48 //   static void OnCreate(...) {
49 //     ...
50 //     // Call OnCreate on the manager object and store the returned pointer.
51 //     tab->state = ctx->manager.OnCreate(argv);
52 //     ...
53 //   }
54 //   static void OnDestroy(...) {
55 //     ...
56 //     // Call OnDestroy with the stored state pointer.
57 //     sqlite::ModuleStateManager<MyModule>::OnDestroy(tab->state);
58 //     ...
59 //   }
60 //   // Do the same in OnConnect and OnDisconnect as in OnCreate and OnDestroy
61 //   // respectively.
62 //   static void OnConnect(...)
63 //   static void OnDisconnect(...)
64 // }
65 template <typename Module>
66 class ModuleStateManager {
67  public:
68   // Per-vtab state. The pointer to this class should be stored in the Vtab.
69   struct PerVtabState {
70    private:
71     // The below fields should only be accessed by the manager, use GetState to
72     // access the state from outside this class.
73     friend class ModuleStateManager<Module>;
74 
75     ModuleStateManager* manager;
76     bool disconnected = false;
77     std::string table_name;
78     std::unique_ptr<typename Module::State> state;
79   };
80 
81   // Lifecycle method to be called from Module::Create.
OnCreate(const char * const * argv,std::unique_ptr<typename Module::State> state)82   [[nodiscard]] PerVtabState* OnCreate(
83       const char* const* argv,
84       std::unique_ptr<typename Module::State> state) {
85     auto it_and_inserted = state_by_name_.Insert(argv[2], nullptr);
86     PERFETTO_CHECK(
87         it_and_inserted.second ||
88         (it_and_inserted.first && it_and_inserted.first->get()->disconnected));
89 
90     auto s = std::make_unique<PerVtabState>();
91     auto* s_ptr = s.get();
92     *it_and_inserted.first = std::move(s);
93 
94     s_ptr->manager = this;
95     s_ptr->table_name = argv[2];
96     s_ptr->state = std::move(state);
97     return it_and_inserted.first->get();
98   }
99 
100   // Lifecycle method to be called from Module::Connect.
OnConnect(const char * const * argv)101   [[nodiscard]] PerVtabState* OnConnect(const char* const* argv) {
102     auto* ptr = state_by_name_.Find(argv[2]);
103     PERFETTO_CHECK(ptr);
104     ptr->get()->disconnected = false;
105     return ptr->get();
106   }
107 
108   // Lifecycle method to be called from Module::Disconnect.
OnDisconnect(PerVtabState * state)109   static void OnDisconnect(PerVtabState* state) {
110     auto* ptr = state->manager->state_by_name_.Find(state->table_name);
111     PERFETTO_CHECK(ptr);
112     ptr->get()->disconnected = true;
113   }
114 
115   // Lifecycle method to be called from Module::Destroy.
OnDestroy(PerVtabState * state)116   static void OnDestroy(PerVtabState* state) {
117     PERFETTO_CHECK(state->manager->state_by_name_.Erase(state->table_name));
118   }
119 
120   // Method to be called from module callbacks to extract the module state
121   // from the manager state.
GetState(PerVtabState * s)122   static typename Module::State* GetState(PerVtabState* s) {
123     return s->state.get();
124   }
125 
126   // Looks up the state of a module by name. This function should only be called
127   // for speculative lookups from outside the module implementation: use
128   // |GetState| inside the sqlite::Module implementation.
FindStateByName(std::string_view name)129   typename Module::State* FindStateByName(std::string_view name) {
130     if (auto ptr = state_by_name_.Find(std::string(name)); ptr) {
131       return GetState(ptr->get());
132     }
133     return nullptr;
134   }
135 
136  private:
137   base::FlatHashMap<std::string, std::unique_ptr<PerVtabState>> state_by_name_;
138 };
139 
140 }  // namespace perfetto::trace_processor::sqlite
141 
142 #endif  // SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_
143