| /* | |
| * Copyright (C) 2019 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. | |
| */ | |
| #include "src/trace_processor/sqlite/module_state_manager.h" | |
| #include <cstdint> | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include <utility> | |
| #include <vector> | |
| #include "perfetto/base/logging.h" | |
| namespace perfetto::trace_processor::sqlite { | |
| void ModuleStateManagerBase::OnCommit() { | |
| std::vector<std::string> to_erase; | |
| for (auto it = state_by_name_.GetIterator(); it; ++it) { | |
| if (auto& state = *it.value(); state.active_state) { | |
| committed_store_->Store(it.key(), state.active_state); | |
| state.savepoint_states.clear(); | |
| } else { | |
| committed_store_->Erase(it.key()); | |
| to_erase.push_back(it.key()); | |
| } | |
| } | |
| for (const auto& name : to_erase) { | |
| state_by_name_.Erase(name); | |
| } | |
| } | |
| void ModuleStateManagerBase::OnRollback() { | |
| std::vector<std::string> to_erase; | |
| for (auto it = state_by_name_.GetIterator(); it; ++it) { | |
| if (auto committed = committed_store_->Load(it.key()); committed) { | |
| auto& state = *it.value(); | |
| state.active_state = std::move(committed); | |
| state.savepoint_states.clear(); | |
| } else { | |
| to_erase.push_back(it.key()); | |
| } | |
| } | |
| for (const auto& name : to_erase) { | |
| state_by_name_.Erase(name); | |
| } | |
| } | |
| ModuleStateManagerBase::PerVtabState* ModuleStateManagerBase::OnCreate( | |
| int, | |
| const char* const* argv, | |
| std::unique_ptr<void, void (*)(void*)> state) { | |
| auto [it, inserted] = state_by_name_.Insert(argv[2], nullptr); | |
| if (inserted) { | |
| *it = std::make_unique<PerVtabState>(); | |
| auto* s_ptr = it->get(); | |
| s_ptr->manager = this; | |
| s_ptr->name = argv[2]; | |
| } | |
| auto* s_ptr = it->get(); | |
| PERFETTO_CHECK(!s_ptr->active_state); | |
| s_ptr->active_state = std::move(state); | |
| return s_ptr; | |
| } | |
| ModuleStateManagerBase::PerVtabState* ModuleStateManagerBase::OnConnect( | |
| int, | |
| const char* const* argv) { | |
| if (auto* ptr = state_by_name_.Find(argv[2]); ptr) { | |
| return ptr->get(); | |
| } | |
| // Cold attach: a peer connection sharing the same |CommittedStateManager| | |
| // may have committed state for this vtab. If so, materialise a local | |
| // |PerVtabState| pointing at the committed state. | |
| auto committed = committed_store_->Load(argv[2]); | |
| if (!committed) { | |
| return nullptr; | |
| } | |
| auto [it, inserted] = state_by_name_.Insert(argv[2], nullptr); | |
| PERFETTO_CHECK(inserted); | |
| *it = std::make_unique<PerVtabState>(); | |
| auto* s_ptr = it->get(); | |
| s_ptr->manager = this; | |
| s_ptr->name = argv[2]; | |
| s_ptr->active_state = std::move(committed); | |
| return s_ptr; | |
| } | |
| void ModuleStateManagerBase::OnDestroy(PerVtabState* state) { | |
| auto* ptr = state->manager->state_by_name_.Find(state->name); | |
| PERFETTO_CHECK(ptr); | |
| PERFETTO_CHECK(ptr->get() == state); | |
| state->active_state.reset(); | |
| } | |
| void ModuleStateManagerBase::OnSavepoint(PerVtabState* s, int idx) { | |
| auto new_size = static_cast<uint32_t>(idx + 1); | |
| std::shared_ptr<void> fill = s->savepoint_states.empty() | |
| ? s->manager->committed_store_->Load(s->name) | |
| : s->savepoint_states.back(); | |
| s->savepoint_states.resize(new_size, std::move(fill)); | |
| s->savepoint_states[new_size - 1] = s->active_state; | |
| } | |
| void ModuleStateManagerBase::OnRelease(PerVtabState* s, int idx) { | |
| auto release_idx = static_cast<uint32_t>(idx); | |
| PERFETTO_CHECK(release_idx <= s->savepoint_states.size()); | |
| s->savepoint_states.resize(release_idx); | |
| } | |
| void ModuleStateManagerBase::OnRollbackTo(PerVtabState* s, int idx) { | |
| auto new_size = static_cast<uint32_t>(idx + 1); | |
| PERFETTO_CHECK(new_size <= s->savepoint_states.size()); | |
| s->active_state = new_size == 0 ? s->manager->committed_store_->Load(s->name) | |
| : s->savepoint_states[new_size - 1]; | |
| s->savepoint_states.resize(new_size); | |
| } | |
| void* ModuleStateManagerBase::GetState(PerVtabState* s) { | |
| return s->active_state.get(); | |
| } | |
| void* ModuleStateManagerBase::GetStateByName(std::string_view name) { | |
| auto* ptr = state_by_name_.Find(name); | |
| if (!ptr) { | |
| return nullptr; | |
| } | |
| return GetState(ptr->get()); | |
| } | |
| } // namespace perfetto::trace_processor::sqlite |