summaryrefslogtreecommitdiff
path: root/src/db/models.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/db/models.h')
-rw-r--r--src/db/models.h1140
1 files changed, 0 insertions, 1140 deletions
diff --git a/src/db/models.h b/src/db/models.h
deleted file mode 100644
index 79823fd..0000000
--- a/src/db/models.h
+++ /dev/null
@@ -1,1140 +0,0 @@
-// 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.
-
-#ifndef IORAP_SRC_DB_MODELS_H_
-#define IORAP_SRC_DB_MODELS_H_
-
-#include "clean_up.h"
-#include "file_models.h"
-
-#include <android-base/logging.h>
-#include <utils/String8.h>
-
-#include <filesystem>
-#include <iostream>
-#include <optional>
-#include <ostream>
-#include <string>
-#include <sstream>
-#include <type_traits>
-#include <vector>
-
-#include <sqlite3.h>
-
-namespace iorap::db {
-
-const constexpr int kDbVersion = 3;
-
-struct SqliteDbDeleter {
- void operator()(sqlite3* db) {
- if (db != nullptr) {
- LOG(VERBOSE) << "sqlite3_close for: " << db;
- sqlite3_close(db);
- }
- }
-};
-
-class DbHandle {
- public:
- // Take over ownership of sqlite3 db.
- explicit DbHandle(sqlite3* db)
- : db_{std::shared_ptr<sqlite3>{db, SqliteDbDeleter{}}},
- mutex_{std::make_shared<std::mutex>()} {
- }
-
- sqlite3* get() {
- return db_.get();
- }
-
- operator sqlite3*() {
- return db_.get();
- }
-
- std::mutex& mutex() {
- return *mutex_.get();
- }
-
- private:
- std::shared_ptr<sqlite3> db_;
- std::shared_ptr<std::mutex> mutex_;
-};
-
-class ScopedLockDb {
- public:
- ScopedLockDb(std::mutex& mutex) : mutex(mutex) {
- mutex.lock();
- }
-
- ScopedLockDb(DbHandle& handle) : ScopedLockDb(handle.mutex()) {
- }
-
- ~ScopedLockDb() {
- mutex.unlock();
- }
- private:
- std::mutex& mutex;
-};
-
-class DbStatement {
- public:
- template <typename ... Args>
- static DbStatement Prepare(DbHandle db, const std::string& sql, Args&&... args) {
- return Prepare(db, sql.c_str(), std::forward<Args>(args)...);
- }
-
- template <typename ... Args>
- static DbStatement Prepare(DbHandle db, const char* sql, Args&&... args) {
- DCHECK(db.get() != nullptr);
- DCHECK(sql != nullptr);
-
- // LOG(VERBOSE) << "Prepare DB=" << db.get();
-
- sqlite3_stmt* stmt = nullptr;
- int rc = sqlite3_prepare_v2(db.get(), sql, -1, /*out*/&stmt, nullptr);
-
- DbStatement db_stmt{db, stmt};
- DCHECK(db_stmt.CheckOk(rc)) << sql;
- db_stmt.BindAll(std::forward<Args>(args)...);
-
- return db_stmt;
- }
-
- DbStatement(DbHandle db, sqlite3_stmt* stmt) : db_(db), stmt_(stmt) {
- }
-
- sqlite3_stmt* get() {
- return stmt_;
- }
-
- DbHandle db() {
- return db_;
- }
-
- // Successive BindAll calls *do not* start back at the 0th bind position.
- template <typename T, typename ... Args>
- void BindAll(T&& arg, Args&&... args) {
- Bind(std::forward<T>(arg));
- BindAll(std::forward<Args>(args)...);
- }
-
- void BindAll() {}
-
- template <typename T>
- void Bind(const std::optional<T>& value) {
- if (value) {
- Bind(*value);
- } else {
- BindNull();
- }
- }
-
- void Bind(bool value) {
- CheckOk(sqlite3_bind_int(stmt_, bind_counter_++, value));
- }
-
- void Bind(int value) {
- CheckOk(sqlite3_bind_int(stmt_, bind_counter_++, value));
- }
-
- void Bind(uint64_t value) {
- CheckOk(sqlite3_bind_int64(stmt_, bind_counter_++, static_cast<int64_t>(value)));
- }
-
- void Bind(const char* value) {
- if (value != nullptr) {
- //sqlite3_bind_text(stmt_, /*index*/bind_counter_++, value, -1, SQLITE_STATIC);
- CheckOk(sqlite3_bind_text(stmt_, /*index*/bind_counter_++, value, -1, SQLITE_TRANSIENT));
- } else {
- BindNull();
- }
- }
-
- void Bind(const std::string& value) {
- Bind(value.c_str());
- }
-
- template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
- void Bind(E value) {
- Bind(static_cast<std::underlying_type_t<E>>(value));
- }
-
- void BindNull() {
- CheckOk(sqlite3_bind_null(stmt_, bind_counter_++));
- }
-
- int Step() {
- ++step_counter_;
- return sqlite3_step(stmt_);
- }
-
- bool Step(int expected) {
- int rc = Step();
- if (rc != expected) {
- LOG(ERROR) << "SQLite error: " << sqlite3_errmsg(db_.get());
- return false;
- }
- return true;
- }
-
- // Successive ColumnAll calls start at the 0th column again.
- template <typename T, typename ... Args>
- void ColumnAll(T& first, Args&... rest) {
- Column(first);
- ColumnAll(rest...);
- // Reset column counter back to 0
- column_counter_ = 0;
- }
-
- void ColumnAll() {}
-
- template <typename T>
- void Column(std::optional<T>& value) {
- T tmp;
- Column(/*out*/tmp);
-
- if (!tmp) { // disambiguate 0 and NULL
- const unsigned char* text = sqlite3_column_text(stmt_, column_counter_ - 1);
- if (text == nullptr) {
- value = std::nullopt;
- return;
- }
- }
- value = std::move(tmp);
- }
-
- template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>>
- void Column(E& value) {
- std::underlying_type_t<E> tmp;
- Column(/*out*/tmp);
- value = static_cast<E>(tmp);
- }
-
- void Column(bool& value) {
- value = sqlite3_column_int(stmt_, column_counter_++);
- }
-
- void Column(int& value) {
- value = sqlite3_column_int(stmt_, column_counter_++);
- }
-
- void Column(uint64_t& value) {
- value = static_cast<uint64_t>(sqlite3_column_int64(stmt_, column_counter_++));
- }
-
- void Column(std::string& value) {
- const unsigned char* text = sqlite3_column_text(stmt_, column_counter_++);
-
- DCHECK(text != nullptr) << "Column should be marked NOT NULL, otherwise use optional<string>";
- if (text == nullptr) {
- LOG(ERROR) << "Got NULL back for column " << column_counter_-1
- << "; is this column marked NOT NULL?";
- value = "(((null)))"; // Don't segfault, keep going.
- return;
- }
-
- value = std::string{reinterpret_cast<const char*>(text)};
- }
-
- const char* ExpandedSql() {
- char* p = sqlite3_expanded_sql(stmt_);
- if (p == nullptr) {
- return "(nullptr)";
- }
- return p;
- }
-
- const char* Sql() {
- const char* p = sqlite3_sql(stmt_);
- if (p == nullptr) {
- return "(nullptr)";
- }
- return p;
- }
-
-
- DbStatement(DbStatement&& other)
- : db_{other.db_}, stmt_{other.stmt_}, bind_counter_{other.bind_counter_},
- step_counter_{other.step_counter_} {
- other.db_ = DbHandle{nullptr};
- other.stmt_ = nullptr;
- }
-
- ~DbStatement() {
- if (stmt_ != nullptr) {
- DCHECK_GT(step_counter_, 0) << " forgot to call Step()?";
- sqlite3_finalize(stmt_);
- }
- }
-
- private:
- bool CheckOk(int rc, int expected = SQLITE_OK) {
- if (rc != expected) {
- LOG(ERROR) << "Got error for SQL query: '" << Sql() << "'"
- << ", expanded: '" << ExpandedSql() << "'";
- LOG(ERROR) << "Failed SQLite api call (" << rc << "): " << sqlite3_errstr(rc);
- }
- return rc == expected;
- }
-
- DbHandle db_;
- sqlite3_stmt* stmt_;
- int bind_counter_ = 1;
- int step_counter_ = 0;
- int column_counter_ = 0;
-};
-
-class DbQueryBuilder {
- public:
- // Returns the row ID that was inserted last.
- template <typename... Args>
- static std::optional<int> Insert(DbHandle db, const std::string& sql, Args&&... args) {
- ScopedLockDb lock{db};
-
- sqlite3_int64 last_rowid = sqlite3_last_insert_rowid(db.get());
- DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
-
- if (!stmt.Step(SQLITE_DONE)) {
- return std::nullopt;
- }
-
- last_rowid = sqlite3_last_insert_rowid(db.get());
- DCHECK_GT(last_rowid, 0);
-
- return static_cast<int>(last_rowid);
- }
-
- template <typename... Args>
- static bool Delete(DbHandle db, const std::string& sql, Args&&... args) {
- return ExecuteOnce(db, sql, std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- static bool Update(DbHandle db, const std::string& sql, Args&&... args) {
- return ExecuteOnce(db, sql, std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- static bool ExecuteOnce(DbHandle db, const std::string& sql, Args&&... args) {
- ScopedLockDb lock{db};
-
- DbStatement stmt = DbStatement::Prepare(db, sql, std::forward<Args>(args)...);
-
- if (!stmt.Step(SQLITE_DONE)) {
- return false;
- }
-
- return true;
- }
-
- template <typename... Args>
- static bool SelectOnce(DbStatement& stmt, Args&... args) {
- int rc = stmt.Step();
- switch (rc) {
- case SQLITE_ROW:
- stmt.ColumnAll(/*out*/args...);
- return true;
- case SQLITE_DONE:
- return false;
- default:
- LOG(ERROR) << "Failed to step (" << rc << "): " << sqlite3_errmsg(stmt.db());
- return false;
- }
- }
-};
-
-class Model {
- public:
- DbHandle db() const {
- return db_;
- }
-
- Model(DbHandle db) : db_{db} {
- }
-
- private:
- DbHandle db_;
-};
-
-class SchemaModel : public Model {
- public:
- static SchemaModel GetOrCreate(std::string location) {
- int rc = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, /*data*/nullptr);
-
- if (rc != SQLITE_OK) {
- LOG(FATAL) << "Failed to configure logging";
- }
-
- sqlite3* db = nullptr;
- bool is_deprecated = false;
- if (location != ":memory:") {
- // Try to open DB if it already exists.
- rc = sqlite3_open_v2(location.c_str(), /*out*/&db, SQLITE_OPEN_READWRITE, /*vfs*/nullptr);
-
- if (rc == SQLITE_OK) {
- LOG(INFO) << "Opened existing database at '" << location << "'";
- SchemaModel schema{DbHandle{db}, location};
- if (schema.Version() == kDbVersion) {
- return schema;
- } else {
- LOG(DEBUG) << "The version is old, reinit the db."
- << " old version is "
- << schema.Version()
- << " and new version is "
- << kDbVersion;
- CleanUpFilesForDb(schema.db());
- is_deprecated = true;
- }
- }
- }
-
- if (is_deprecated) {
- // Remove the db and recreate it.
- // TODO: migrate to a newer version without deleting the old one.
- std::filesystem::remove(location.c_str());
- }
-
- // Create a new DB if one didn't exist already.
- rc = sqlite3_open(location.c_str(), /*out*/&db);
-
- if (rc != SQLITE_OK) {
- LOG(FATAL) << "Failed to open DB: " << sqlite3_errmsg(db);
- }
-
- SchemaModel schema{DbHandle{db}, location};
- schema.Reinitialize();
- // TODO: migrate versions upwards when we rev the schema version
-
- int old_version = schema.Version();
- LOG(VERBOSE) << "Loaded schema version: " << old_version;
-
- return schema;
- }
-
- void MarkSingleton() {
- s_singleton_ = db();
- }
-
- static DbHandle GetSingleton() {
- DCHECK(s_singleton_.has_value());
- return *s_singleton_;
- }
-
- void Reinitialize() {
- const char* sql_to_initialize = R"SQLC0D3(
- DROP TABLE IF EXISTS schema_versions;
- DROP TABLE IF EXISTS packages;
- DROP TABLE IF EXISTS activities;
- DROP TABLE IF EXISTS app_launch_histories;
- DROP TABLE IF EXISTS raw_traces;
- DROP TABLE IF EXISTS prefetch_files;
-)SQLC0D3";
- char* err_msg = nullptr;
- int rc = sqlite3_exec(db().get(),
- sql_to_initialize,
- /*callback*/nullptr,
- /*arg*/0,
- /*out*/&err_msg);
- if (rc != SQLITE_OK) {
- LOG(FATAL) << "Failed to drop tables: " << err_msg ? err_msg : "nullptr";
- }
-
- CreateSchema();
- LOG(INFO) << "Reinitialized database at '" << location_ << "'";
- }
-
- int Version() {
- std::string query = "SELECT MAX(version) FROM schema_versions;";
- DbStatement stmt = DbStatement::Prepare(db(), query);
-
- int return_value = 0;
- if (!DbQueryBuilder::SelectOnce(stmt, /*out*/return_value)) {
- LOG(ERROR) << "Failed to query schema version";
- return -1;
- }
-
- return return_value;
- }
-
- protected:
- SchemaModel(DbHandle db, std::string location) : Model{db}, location_(location) {
- }
-
- private:
- static std::optional<DbHandle> s_singleton_;
-
- void CreateSchema() {
- const char* sql_to_initialize = R"SQLC0D3(
- CREATE TABLE schema_versions(
- version INTEGER NOT NULL
- );
-
- CREATE TABLE packages(
- id INTEGER NOT NULL,
- name TEXT NOT NULL,
- version INTEGER NOT NULL,
-
- PRIMARY KEY(id)
- );
-
- CREATE TABLE activities(
- id INTEGER NOT NULL,
- name TEXT NOT NULL,
- package_id INTEGER NOT NULL,
-
- PRIMARY KEY(id),
- FOREIGN KEY (package_id) REFERENCES packages (id) ON DELETE CASCADE
- );
-
- CREATE TABLE app_launch_histories(
- id INTEGER NOT NULL PRIMARY KEY,
- activity_id INTEGER NOT NULL,
- -- 1:Cold, 2:Warm, 3:Hot
- temperature INTEGER CHECK (temperature IN (1, 2, 3)) NOT NULL,
- trace_enabled INTEGER CHECK(trace_enabled in (TRUE, FALSE)) NOT NULL,
- readahead_enabled INTEGER CHECK(trace_enabled in (TRUE, FALSE)) NOT NULL,
- -- absolute timestamp since epoch
- intent_started_ns INTEGER CHECK(intent_started_ns IS NULL or intent_started_ns >= 0),
- -- absolute timestamp since epoch
- total_time_ns INTEGER CHECK(total_time_ns IS NULL or total_time_ns >= 0),
- -- absolute timestamp since epoch
- report_fully_drawn_ns INTEGER CHECK(report_fully_drawn_ns IS NULL or report_fully_drawn_ns >= 0),
- -- pid of the app
- pid INTEGER CHECK(pid IS NULL or pid >= 0),
-
- FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
- );
-
- CREATE TABLE raw_traces(
- id INTEGER NOT NULL PRIMARY KEY,
- history_id INTEGER NOT NULL,
- file_path TEXT NOT NULL,
-
- FOREIGN KEY (history_id) REFERENCES app_launch_histories (id) ON DELETE CASCADE
- );
-
- CREATE TABLE prefetch_files(
- id INTEGER NOT NULL PRIMARY KEY,
- activity_id INTEGER NOT NULL,
- file_path TEXT NOT NULL,
-
- FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
- );
-)SQLC0D3";
-
- char* err_msg = nullptr;
- int rc = sqlite3_exec(db().get(),
- sql_to_initialize,
- /*callback*/nullptr,
- /*arg*/0,
- /*out*/&err_msg);
-
- if (rc != SQLITE_OK) {
- LOG(FATAL) << "Failed to create tables: " << err_msg ? err_msg : "nullptr";
- }
-
- const char* sql_to_insert_schema_version = R"SQLC0D3(
- INSERT INTO schema_versions VALUES(%d)
- )SQLC0D3";
- rc = sqlite3_exec(db().get(),
- android::String8::format(sql_to_insert_schema_version,
- kDbVersion),
- /*callback*/nullptr,
- /*arg*/0,
- /*out*/&err_msg);
-
- if (rc != SQLITE_OK) {
- LOG(FATAL) << "Failed to insert the schema version: "
- << err_msg ? err_msg : "nullptr";
- }
- }
-
- static void ErrorLogCallback(void *pArg, int iErrCode, const char *zMsg) {
- LOG(ERROR) << "SQLite error (" << iErrCode << "): " << zMsg;
- }
-
- std::string location_;
-};
-
-class PackageModel : public Model {
- protected:
- PackageModel(DbHandle db) : Model{db} {
- }
-
- public:
- static std::optional<PackageModel> SelectById(DbHandle db, int id) {
- ScopedLockDb lock{db};
- int original_id = id;
-
- std::string query = "SELECT * FROM packages WHERE id = ?1 LIMIT 1;";
- DbStatement stmt = DbStatement::Prepare(db, query, id);
-
- PackageModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::vector<PackageModel> SelectByName(DbHandle db, const char* name) {
- ScopedLockDb lock{db};
-
- std::string query = "SELECT * FROM packages WHERE name = ?1;";
- DbStatement stmt = DbStatement::Prepare(db, query, name);
-
- std::vector<PackageModel> packages;
-
- PackageModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
- packages.push_back(p);
- }
-
- return packages;
- }
-
- static std::optional<PackageModel> SelectByNameAndVersion(DbHandle db,
- const char* name,
- int version) {
- ScopedLockDb lock{db};
-
- std::string query =
- "SELECT * FROM packages WHERE name = ?1 AND version = ?2 LIMIT 1;";
- DbStatement stmt = DbStatement::Prepare(db, query, name, version);
-
- PackageModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::vector<PackageModel> SelectAll(DbHandle db) {
- ScopedLockDb lock{db};
-
- std::string query = "SELECT * FROM packages;";
- DbStatement stmt = DbStatement::Prepare(db, query);
-
- std::vector<PackageModel> packages;
- PackageModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.version)) {
- packages.push_back(p);
- }
-
- return packages;
- }
-
- static std::optional<PackageModel> Insert(DbHandle db,
- std::string name,
- int version) {
- const char* sql = "INSERT INTO packages (name, version) VALUES (?1, ?2);";
-
- std::optional<int> inserted_row_id =
- DbQueryBuilder::Insert(db, sql, name, version);
- if (!inserted_row_id) {
- return std::nullopt;
- }
-
- PackageModel p{db};
- p.name = name;
- p.version = version;
- p.id = *inserted_row_id;
-
- return p;
- }
-
- bool Delete() {
- const char* sql = "DELETE FROM packages WHERE id = ?";
-
- return DbQueryBuilder::Delete(db(), sql, id);
- }
-
- int id;
- std::string name;
- int version;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const PackageModel& p) {
- os << "PackageModel{id=" << p.id << ",name=" << p.name << ",";
- os << "version=";
- os << p.version;
- os << "}";
- return os;
-}
-
-class ActivityModel : public Model {
- protected:
- ActivityModel(DbHandle db) : Model{db} {
- }
-
- public:
- static std::optional<ActivityModel> SelectById(DbHandle db, int id) {
- ScopedLockDb lock{db};
- int original_id = id;
-
- std::string query = "SELECT * FROM activities WHERE id = ? LIMIT 1;";
- DbStatement stmt = DbStatement::Prepare(db, query, id);
-
- ActivityModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::optional<ActivityModel> SelectByNameAndPackageId(DbHandle db,
- const char* name,
- int package_id) {
- ScopedLockDb lock{db};
-
- std::string query = "SELECT * FROM activities WHERE name = ? AND package_id = ? LIMIT 1;";
- DbStatement stmt = DbStatement::Prepare(db, query, name, package_id);
-
- ActivityModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::vector<ActivityModel> SelectByPackageId(DbHandle db,
- int package_id) {
- ScopedLockDb lock{db};
-
- std::string query = "SELECT * FROM activities WHERE package_id = ?;";
- DbStatement stmt = DbStatement::Prepare(db, query, package_id);
-
- std::vector<ActivityModel> activities;
- ActivityModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt, p.id, p.name, p.package_id)) {
- activities.push_back(p);
- }
-
- return activities;
- }
-
- static std::optional<ActivityModel> Insert(DbHandle db,
- std::string name,
- int package_id) {
- const char* sql = "INSERT INTO activities (name, package_id) VALUES (?1, ?2);";
-
- std::optional<int> inserted_row_id =
- DbQueryBuilder::Insert(db, sql, name, package_id);
- if (!inserted_row_id) {
- return std::nullopt;
- }
-
- ActivityModel p{db};
- p.id = *inserted_row_id;
- p.name = name;
- p.package_id = package_id;
-
- return p;
- }
-
- // Try to select by package_name+activity_name, otherwise insert into both tables.
- // Package version is ignored for selects.
- static std::optional<ActivityModel> SelectOrInsert(
- DbHandle db,
- std::string package_name,
- int package_version,
- std::string activity_name) {
- std::optional<PackageModel> package = PackageModel::SelectByNameAndVersion(db,
- package_name.c_str(),
- package_version);
- if (!package) {
- package = PackageModel::Insert(db, package_name, package_version);
- DCHECK(package.has_value());
- }
-
- std::optional<ActivityModel> activity =
- ActivityModel::SelectByNameAndPackageId(db,
- activity_name.c_str(),
- package->id);
- if (!activity) {
- activity = Insert(db, activity_name, package->id);
- // XX: should we really return an optional here? This feels like it should never fail.
- }
-
- return activity;
- }
-
- int id;
- std::string name;
- int package_id; // PackageModel::id
-};
-
-inline std::ostream& operator<<(std::ostream& os, const ActivityModel& p) {
- os << "ActivityModel{id=" << p.id << ",name=" << p.name << ",";
- os << "package_id=" << p.package_id << "}";
- return os;
-}
-
-class AppLaunchHistoryModel : public Model {
- protected:
- AppLaunchHistoryModel(DbHandle db) : Model{db} {
- }
-
- public:
- enum class Temperature : int32_t {
- kUninitialized = -1, // Note: Not a valid SQL value.
- kCold = 1,
- kWarm = 2,
- kHot = 3,
- };
-
- static std::optional<AppLaunchHistoryModel> SelectById(DbHandle db, int id) {
- ScopedLockDb lock{db};
- int original_id = id;
-
- std::string query = "SELECT * FROM app_launch_histories WHERE id = ? LIMIT 1;";
- DbStatement stmt = DbStatement::Prepare(db, query, id);
-
- AppLaunchHistoryModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt,
- p.id,
- p.activity_id,
- p.temperature,
- p.trace_enabled,
- p.readahead_enabled,
- p.intent_started_ns,
- p.total_time_ns,
- p.report_fully_drawn_ns,
- p.pid)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- // Selects the activity history for an activity id.
- // The requirements are:
- // * Should be cold run.
- // * Pefetto trace is enabled.
- // * intent_start_ns is *NOT* null.
- static std::vector<AppLaunchHistoryModel> SelectActivityHistoryForCompile(
- DbHandle db,
- int activity_id) {
- ScopedLockDb lock{db};
- std::string query = "SELECT * FROM app_launch_histories "
- "WHERE activity_id = ?1 AND"
- " temperature = 1 AND"
- " trace_enabled = TRUE AND"
- " intent_started_ns IS NOT NULL;";
- DbStatement stmt = DbStatement::Prepare(db, query, activity_id);
- std::vector<AppLaunchHistoryModel> result;
-
- AppLaunchHistoryModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt,
- p.id,
- p.activity_id,
- p.temperature,
- p.trace_enabled,
- p.readahead_enabled,
- p.intent_started_ns,
- p.total_time_ns,
- p.report_fully_drawn_ns,
- p.pid)) {
- result.push_back(p);
- }
- return result;
- }
-
- static std::optional<AppLaunchHistoryModel> Insert(DbHandle db,
- int activity_id,
- AppLaunchHistoryModel::Temperature temperature,
- bool trace_enabled,
- bool readahead_enabled,
- std::optional<uint64_t> intent_started_ns,
- std::optional<uint64_t> total_time_ns,
- std::optional<uint64_t> report_fully_drawn_ns,
- int32_t pid)
- {
- const char* sql = "INSERT INTO app_launch_histories (activity_id, temperature, trace_enabled, "
- "readahead_enabled, intent_started_ns, "
- "total_time_ns, report_fully_drawn_ns, pid) "
- "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
-
- std::optional<int> inserted_row_id =
- DbQueryBuilder::Insert(db,
- sql,
- activity_id,
- temperature,
- trace_enabled,
- readahead_enabled,
- intent_started_ns,
- total_time_ns,
- report_fully_drawn_ns,
- pid);
- if (!inserted_row_id) {
- return std::nullopt;
- }
-
- AppLaunchHistoryModel p{db};
- p.id = *inserted_row_id;
- p.activity_id = activity_id;
- p.temperature = temperature;
- p.trace_enabled = trace_enabled;
- p.readahead_enabled = readahead_enabled;
- p.intent_started_ns = intent_started_ns;
- p.total_time_ns = total_time_ns;
- p.report_fully_drawn_ns = report_fully_drawn_ns;
- p.pid = pid;
-
- return p;
- }
-
- static bool UpdateReportFullyDrawn(DbHandle db,
- int history_id,
- uint64_t report_fully_drawn_ns)
- {
- const char* sql = "UPDATE app_launch_histories "
- "SET report_fully_drawn_ns = ?1 "
- "WHERE id = ?2;";
-
- bool result = DbQueryBuilder::Update(db, sql, report_fully_drawn_ns, history_id);
-
- if (!result) {
- LOG(ERROR)<< "Failed to update history_id:"<< history_id
- << ", report_fully_drawn_ns: " << report_fully_drawn_ns;
- }
- return result;
- }
-
- int id;
- int activity_id; // ActivityModel::id
- Temperature temperature = Temperature::kUninitialized;
- bool trace_enabled;
- bool readahead_enabled;
- std::optional<uint64_t> intent_started_ns;
- std::optional<uint64_t> total_time_ns;
- std::optional<uint64_t> report_fully_drawn_ns;
- int32_t pid;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const AppLaunchHistoryModel& p) {
- os << "AppLaunchHistoryModel{id=" << p.id << ","
- << "activity_id=" << p.activity_id << ","
- << "temperature=" << static_cast<int>(p.temperature) << ","
- << "trace_enabled=" << p.trace_enabled << ","
- << "readahead_enabled=" << p.readahead_enabled << ","
- << "intent_started_ns=";
- if (p.intent_started_ns) {
- os << *p.intent_started_ns;
- } else {
- os << "(nullopt)";
- }
- os << ",";
- os << "total_time_ns=";
- if (p.total_time_ns) {
- os << *p.total_time_ns;
- } else {
- os << "(nullopt)";
- }
- os << ",";
- os << "report_fully_drawn_ns=";
- if (p.report_fully_drawn_ns) {
- os << *p.report_fully_drawn_ns;
- } else {
- os << "(nullopt)";
- }
- os << ",";
- os << "pid=" << p.pid;
- os << "}";
- return os;
-}
-
-class RawTraceModel : public Model {
- protected:
- RawTraceModel(DbHandle db) : Model{db} {
- }
-
- public:
-
- // Return raw_traces, sorted ascending by the id.
- static std::vector<RawTraceModel> SelectByVersionedComponentName(DbHandle db,
- VersionedComponentName vcn) {
- ScopedLockDb lock{db};
-
- const char* sql =
- "SELECT raw_traces.id, raw_traces.history_id, raw_traces.file_path "
- "FROM raw_traces "
- "INNER JOIN app_launch_histories ON raw_traces.history_id = app_launch_histories.id "
- "INNER JOIN activities ON activities.id = app_launch_histories.activity_id "
- "INNER JOIN packages ON packages.id = activities.package_id "
- "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?"
- "ORDER BY raw_traces.id ASC";
-
- DbStatement stmt = DbStatement::Prepare(db,
- sql,
- vcn.GetPackage(),
- vcn.GetActivity(),
- vcn.GetVersion());
-
- std::vector<RawTraceModel> results;
-
- RawTraceModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt, p.id, p.history_id, p.file_path)) {
- results.push_back(p);
- }
-
- return results;
- }
-
- static std::optional<RawTraceModel> SelectByHistoryId(DbHandle db, int history_id) {
- ScopedLockDb lock{db};
-
- const char* sql =
- "SELECT id, history_id, file_path "
- "FROM raw_traces "
- "WHERE history_id = ?1 "
- "LIMIT 1;";
-
- DbStatement stmt = DbStatement::Prepare(db, sql, history_id);
-
- RawTraceModel p{db};
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.history_id, p.file_path)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::optional<RawTraceModel> Insert(DbHandle db,
- int history_id,
- std::string file_path) {
- const char* sql = "INSERT INTO raw_traces (history_id, file_path) VALUES (?1, ?2);";
-
- std::optional<int> inserted_row_id =
- DbQueryBuilder::Insert(db, sql, history_id, file_path);
- if (!inserted_row_id) {
- return std::nullopt;
- }
-
- RawTraceModel p{db};
- p.id = *inserted_row_id;
- p.history_id = history_id;
- p.file_path = file_path;
-
- return p;
- }
-
- bool Delete() {
- const char* sql = "DELETE FROM raw_traces WHERE id = ?";
-
- return DbQueryBuilder::Delete(db(), sql, id);
- }
-
- int id;
- int history_id;
- std::string file_path;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const RawTraceModel& p) {
- os << "RawTraceModel{id=" << p.id << ",history_id=" << p.history_id << ",";
- os << "file_path=" << p.file_path << "}";
- return os;
-}
-
-class PrefetchFileModel : public Model {
- protected:
- PrefetchFileModel(DbHandle db) : Model{db} {
- }
-
- public:
- static std::optional<PrefetchFileModel> SelectByVersionedComponentName(
- DbHandle db,
- VersionedComponentName vcn) {
- ScopedLockDb lock{db};
-
- const char* sql =
- "SELECT prefetch_files.id, prefetch_files.activity_id, prefetch_files.file_path "
- "FROM prefetch_files "
- "INNER JOIN activities ON activities.id = prefetch_files.activity_id "
- "INNER JOIN packages ON packages.id = activities.package_id "
- "WHERE packages.name = ? AND activities.name = ? AND packages.version = ?";
-
- DbStatement stmt = DbStatement::Prepare(db,
- sql,
- vcn.GetPackage(),
- vcn.GetActivity(),
- vcn.GetVersion());
-
- PrefetchFileModel p{db};
-
- if (!DbQueryBuilder::SelectOnce(stmt, p.id, p.activity_id, p.file_path)) {
- return std::nullopt;
- }
-
- return p;
- }
-
- static std::vector<PrefetchFileModel> SelectAll(DbHandle db) {
- ScopedLockDb lock{db};
-
- std::string query =
- "SELECT prefetch_files.id, prefetch_files.activity_id, prefetch_files.file_path "
- "FROM prefetch_files";
- DbStatement stmt = DbStatement::Prepare(db, query);
-
- std::vector<PrefetchFileModel> prefetch_files;
- PrefetchFileModel p{db};
- while (DbQueryBuilder::SelectOnce(stmt, p.id, p.activity_id, p.file_path)) {
- prefetch_files.push_back(p);
- }
-
- return prefetch_files;
- }
-
- static std::optional<PrefetchFileModel> Insert(DbHandle db,
- int activity_id,
- std::string file_path) {
- const char* sql = "INSERT INTO prefetch_files (activity_id, file_path) VALUES (?1, ?2);";
-
- std::optional<int> inserted_row_id =
- DbQueryBuilder::Insert(db, sql, activity_id, file_path);
- if (!inserted_row_id) {
- return std::nullopt;
- }
-
- PrefetchFileModel p{db};
- p.id = *inserted_row_id;
- p.activity_id = activity_id;
- p.file_path = file_path;
-
- return p;
- }
-
- bool Delete() {
- const char* sql = "DELETE FROM prefetch_files WHERE id = ?";
-
- return DbQueryBuilder::Delete(db(), sql, id);
- }
-
- int id;
- int activity_id;
- std::string file_path;
-};
-
-inline std::ostream& operator<<(std::ostream& os, const PrefetchFileModel& p) {
- os << "PrefetchFileModel{id=" << p.id << ",activity_id=" << p.activity_id << ",";
- os << "file_path=" << p.file_path << "}";
- return os;
-}
-
-} // namespace iorap::db
-
-#endif // IORAP_SRC_DB_MODELS_H_