1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include <iostream>
16
17 #include "tensorflow/core/lib/db/sqlite.h"
18 #include "tensorflow/core/platform/init_main.h"
19 #include "tensorflow/core/util/command_line_flags.h"
20
21 namespace tensorflow {
22 namespace {
23
Vacuum(const char * path)24 void Vacuum(const char* path) {
25 LOG(INFO) << "Opening SQLite DB: " << path;
26 Sqlite* db;
27 TF_CHECK_OK(Sqlite::Open(path, SQLITE_OPEN_READWRITE, &db));
28 core::ScopedUnref db_unref(db);
29
30 // TODO(jart): Maybe defragment rowids on Tensors.
31 // TODO(jart): Maybe LIMIT deletes and incremental VACUUM.
32
33 // clang-format off
34
35 LOG(INFO) << "Deleting orphaned Experiments";
36 db->PrepareOrDie(R"sql(
37 DELETE FROM
38 Experiments
39 WHERE
40 user_id IS NOT NULL
41 AND user_id NOT IN (SELECT user_id FROM Users)
42 )sql").StepAndResetOrDie();
43
44 LOG(INFO) << "Deleting orphaned Runs";
45 db->PrepareOrDie(R"sql(
46 DELETE FROM
47 Runs
48 WHERE
49 experiment_id IS NOT NULL
50 AND experiment_id NOT IN (SELECT experiment_id FROM Experiments)
51 )sql").StepAndResetOrDie();
52
53 LOG(INFO) << "Deleting orphaned Tags";
54 db->PrepareOrDie(R"sql(
55 DELETE FROM
56 Tags
57 WHERE
58 run_id IS NOT NULL
59 AND run_id NOT IN (SELECT run_id FROM Runs)
60 )sql").StepAndResetOrDie();
61
62 // TODO(jart): What should we do if plugins define non-tag tensor series?
63 LOG(INFO) << "Deleting orphaned Tensors";
64 db->PrepareOrDie(R"sql(
65 DELETE FROM
66 Tensors
67 WHERE
68 series IS NOT NULL
69 AND series NOT IN (SELECT tag_id FROM Tags)
70 )sql").StepAndResetOrDie();
71
72 LOG(INFO) << "Deleting orphaned TensorStrings";
73 db->PrepareOrDie(R"sql(
74 DELETE FROM
75 TensorStrings
76 WHERE
77 tensor_rowid NOT IN (SELECT rowid FROM Tensors)
78 )sql").StepAndResetOrDie();
79
80 LOG(INFO) << "Deleting orphaned Graphs";
81 db->PrepareOrDie(R"sql(
82 DELETE FROM
83 Graphs
84 WHERE
85 run_id IS NOT NULL
86 AND run_id NOT IN (SELECT run_id FROM Runs)
87 )sql").StepAndResetOrDie();
88
89 LOG(INFO) << "Deleting orphaned Nodes";
90 db->PrepareOrDie(R"sql(
91 DELETE FROM
92 Nodes
93 WHERE
94 graph_id NOT IN (SELECT graph_id FROM Graphs)
95 )sql").StepAndResetOrDie();
96
97 LOG(INFO) << "Deleting orphaned NodeInputs";
98 db->PrepareOrDie(R"sql(
99 DELETE FROM
100 NodeInputs
101 WHERE
102 graph_id NOT IN (SELECT graph_id FROM Graphs)
103 )sql").StepAndResetOrDie();
104
105 LOG(INFO) << "Running VACUUM";
106 db->PrepareOrDie("VACUUM").StepAndResetOrDie();
107
108 // clang-format on
109 }
110
main(int argc,char * argv[])111 int main(int argc, char* argv[]) {
112 string usage = Flags::Usage(argv[0], {});
113 bool parse_result = Flags::Parse(&argc, argv, {});
114 if (!parse_result) {
115 std::cerr << "The vacuum tool rebuilds SQLite database files created by\n"
116 << "SummaryDbWriter, which makes them smaller.\n\n"
117 << "This means deleting orphaned rows and rebuilding b-tree\n"
118 << "pages so empty space from deleted rows is cleared. Any\n"
119 << "superfluous padding of Tensor BLOBs is also removed.\n\n"
120 << usage;
121 return -1;
122 }
123 port::InitMain(argv[0], &argc, &argv);
124 if (argc < 2 || argv[1][0] == '-') {
125 std::cerr << "Need at least one SQLite DB path.\n";
126 return -1;
127 }
128 for (int i = 1; i < argc; ++i) {
129 Vacuum(argv[i]);
130 }
131 return 0;
132 }
133
134 } // namespace
135 } // namespace tensorflow
136
main(int argc,char * argv[])137 int main(int argc, char* argv[]) { return tensorflow::main(argc, argv); }
138