• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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