Trace Processor: Add RestoreInitialTables() method
Deletes all tables and views created by the user/UI
after loadinig the trace. Will be used by the UI with
the RPC+HTTP mode to reuse the same trace processor
instance.
Bug: 143074239
Change-Id: I4cefb0f8cbd7e6bec9124b0208a128d568698484
diff --git a/include/perfetto/trace_processor/trace_processor.h b/include/perfetto/trace_processor/trace_processor.h
index f6f5089..13f45c8 100644
--- a/include/perfetto/trace_processor/trace_processor.h
+++ b/include/perfetto/trace_processor/trace_processor.h
@@ -117,6 +117,11 @@
// Interrupts the current query. Typically used by Ctrl-C handler.
virtual void InterruptQuery() = 0;
+
+ // Deletes all tables and view that have been create (by the UI or user) after
+ // the trace was loaded. It preserves the built-in tables/view created by the
+ // loading process. Returns the number of table/views deleted.
+ virtual size_t RestoreInitialTables() = 0;
};
// When set, logs SQLite actions on the console.
diff --git a/src/trace_processor/trace_database_integrationtest.cc b/src/trace_processor/trace_database_integrationtest.cc
index 0392c85..4d7d007 100644
--- a/src/trace_processor/trace_database_integrationtest.cc
+++ b/src/trace_processor/trace_database_integrationtest.cc
@@ -56,6 +56,8 @@
return processor_->ExecuteQuery(query.c_str());
}
+ size_t RestoreInitialTables() { return processor_->RestoreInitialTables(); }
+
private:
std::unique_ptr<TraceProcessor> processor_;
};
@@ -179,6 +181,28 @@
ASSERT_TRUE(LoadTrace("clusterfuzz_17805", 4096).ok());
}
+TEST_F(TraceProcessorIntegrationTest, RestoreInitialTables) {
+ ASSERT_TRUE(LoadTrace("android_sched_and_ps.pb").ok());
+
+ for (int repeat = 0; repeat < 3; repeat++) {
+ ASSERT_EQ(RestoreInitialTables(), 0u);
+
+ auto it = Query("CREATE TABLE user1(unused text);");
+ it.Next();
+ ASSERT_TRUE(it.Status().ok());
+
+ it = Query("CREATE TEMPORARY TABLE user2(unused text);");
+ it.Next();
+ ASSERT_TRUE(it.Status().ok());
+
+ it = Query("CREATE VIEW user3 AS SELECT * FROM stats;");
+ it.Next();
+ ASSERT_TRUE(it.Status().ok());
+
+ ASSERT_EQ(RestoreInitialTables(), 3u);
+ }
+}
+
} // namespace
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index f6a9dd3..0944d19 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -97,6 +97,10 @@
namespace trace_processor {
namespace {
+const char kAllTablesQuery[] =
+ "SELECT tbl_name, type FROM (SELECT * FROM sqlite_master UNION ALL SELECT "
+ "* FROM sqlite_temp_master)";
+
void InitializeSqlite(sqlite3* db) {
char* error = nullptr;
sqlite3_exec(db, "PRAGMA temp_store=2", 0, 0, &error);
@@ -440,6 +444,41 @@
context_.event_tracker->FlushPendingEvents();
context_.slice_tracker->FlushPendingSlices();
BuildBoundsTable(*db_, context_.storage->GetTraceTimestampBoundsNs());
+
+ // Create a snapshot of all tables and views created so far. This is so later
+ // we can drop all extra tables created by the UI and reset to the original
+ // state (see RestoreInitialTables).
+ initial_tables_.clear();
+ auto it = ExecuteQuery(kAllTablesQuery);
+ while (it.Next()) {
+ auto value = it.Get(0);
+ PERFETTO_CHECK(value.type == SqlValue::Type::kString);
+ initial_tables_.push_back(value.string_value);
+ }
+}
+
+size_t TraceProcessorImpl::RestoreInitialTables() {
+ std::vector<std::pair<std::string, std::string>> deletion_list;
+ std::string msg = "Resetting DB to initial state, deleting table/views:";
+ for (auto it = ExecuteQuery(kAllTablesQuery); it.Next();) {
+ std::string name(it.Get(0).string_value);
+ std::string type(it.Get(1).string_value);
+ if (std::find(initial_tables_.begin(), initial_tables_.end(), name) ==
+ initial_tables_.end()) {
+ msg += " " + name;
+ deletion_list.push_back(std::make_pair(type, name));
+ }
+ }
+
+ PERFETTO_LOG("%s", msg.c_str());
+ for (const auto& tn : deletion_list) {
+ std::string query = "DROP " + tn.first + " " + tn.second;
+ auto it = ExecuteQuery(query);
+ while (it.Next()) {
+ }
+ PERFETTO_CHECK(it.Status().ok());
+ }
+ return deletion_list.size();
}
TraceProcessor::Iterator TraceProcessorImpl::ExecuteQuery(
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index 0f61c2b..44c3335 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -22,6 +22,7 @@
#include <atomic>
#include <functional>
#include <memory>
+#include <string>
#include <vector>
#include "perfetto/ext/base/string_view.h"
@@ -67,6 +68,8 @@
void InterruptQuery() override;
+ size_t RestoreInitialTables() override;
+
TraceProcessorContext* context() { return &context_; }
private:
@@ -87,6 +90,11 @@
// This is atomic because it is set by the CTRL-C signal handler and we need
// to prevent single-flow compiler optimizations in ExecuteQuery().
std::atomic<bool> query_interrupted_{false};
+
+ // Keeps track of the tables created by the ingestion process. This is used
+ // by RestoreInitialTables() to delete all the tables/view that have been
+ // created after that point.
+ std::vector<std::string> initial_tables_;
};
// The pointer implementation of TraceProcessor::Iterator.
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index 25ffb6f..3745634 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -444,7 +444,8 @@
"Available commands:\n"
".quit, .q Exit the shell.\n"
".help This text.\n"
- ".dump FILE Export the trace as a sqlite database.\n");
+ ".dump FILE Export the trace as a sqlite database.\n"
+ ".reset Destroys all tables/view created by the user.\n");
}
int StartInteractiveShell(uint32_t column_width) {
@@ -467,6 +468,8 @@
} else if (strcmp(command, "dump") == 0 && strlen(arg)) {
if (ExportTraceToDatabase(arg) != 0)
PERFETTO_ELOG("Database export failed");
+ } else if (strcmp(command, "reset") == 0) {
+ g_tp->RestoreInitialTables();
} else {
PrintShellUsage();
}