/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_ #define SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_ #include #include #include #include "perfetto/base/logging.h" #include "perfetto/ext/base/flat_hash_map.h" namespace perfetto::trace_processor::sqlite { // Helper class which abstracts away management of per-vtab state of an SQLite // virtual table module. // // SQLite has some subtle semantics around lifecycle of vtabs which makes state // management complex. This class attempts to encapsulate some of that // complexity as a central place where we can document the quirks. // // Usage of this class: // struct MyModule : sqlite::Module { // struct Context { // // Store the manager in the context object. // ModuleStateManager manager. // ... (other fields) // } // struct Vtab : sqlite::Module::Vtab { // // Store the per-vtab-state pointer in the vtab object. // ModuleStateManager::PerVtabState* state; // ... (other fields) // } // static void OnCreate(...) { // ... // // Call OnCreate on the manager object and store the returned pointer. // tab->state = ctx->manager.OnCreate(argv); // ... // } // static void OnDestroy(...) { // ... // // Call OnDestroy with the stored state pointer. // sqlite::ModuleStateManager::OnDestroy(tab->state); // ... // } // // Do the same in OnConnect and OnDisconnect as in OnCreate and OnDestroy // // respectively. // static void OnConnect(...) // static void OnDisconnect(...) // } template class ModuleStateManager { public: // Per-vtab state. The pointer to this class should be stored in the Vtab. struct PerVtabState { private: // The below fields should only be accessed by the manager, use GetState to // access the state from outside this class. friend class ModuleStateManager; ModuleStateManager* manager; bool disconnected = false; std::string table_name; std::unique_ptr state; }; // Lifecycle method to be called from Module::Create. [[nodiscard]] PerVtabState* OnCreate( const char* const* argv, std::unique_ptr state) { auto it_and_inserted = state_by_name_.Insert(argv[2], nullptr); PERFETTO_CHECK( it_and_inserted.second || (it_and_inserted.first && it_and_inserted.first->get()->disconnected)); auto s = std::make_unique(); auto* s_ptr = s.get(); *it_and_inserted.first = std::move(s); s_ptr->manager = this; s_ptr->table_name = argv[2]; s_ptr->state = std::move(state); return it_and_inserted.first->get(); } // Lifecycle method to be called from Module::Connect. [[nodiscard]] PerVtabState* OnConnect(const char* const* argv) { auto* ptr = state_by_name_.Find(argv[2]); PERFETTO_CHECK(ptr); ptr->get()->disconnected = false; return ptr->get(); } // Lifecycle method to be called from Module::Disconnect. static void OnDisconnect(PerVtabState* state) { auto* ptr = state->manager->state_by_name_.Find(state->table_name); PERFETTO_CHECK(ptr); ptr->get()->disconnected = true; } // Lifecycle method to be called from Module::Destroy. static void OnDestroy(PerVtabState* state) { PERFETTO_CHECK(state->manager->state_by_name_.Erase(state->table_name)); } // Method to be called from module callbacks to extract the module state // from the manager state. static typename Module::State* GetState(PerVtabState* s) { return s->state.get(); } // Looks up the state of a module by name. This function should only be called // for speculative lookups from outside the module implementation: use // |GetState| inside the sqlite::Module implementation. typename Module::State* FindStateByName(std::string_view name) { if (auto ptr = state_by_name_.Find(std::string(name)); ptr) { return GetState(ptr->get()); } return nullptr; } private: base::FlatHashMap> state_by_name_; }; } // namespace perfetto::trace_processor::sqlite #endif // SRC_TRACE_PROCESSOR_SQLITE_MODULE_LIFECYCLE_MANAGER_H_