1 package gov.usgs.volcanoes.winston.db;
2
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5 import java.sql.Statement;
6 import java.util.Iterator;
7 import java.util.List;
8
9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory;
11
12 import gov.usgs.volcanoes.core.configfile.ConfigFile;
13 import gov.usgs.volcanoes.winston.Channel;
14
15
16
17
18
19 public class Admin {
20 private static final Logger LOGGER = LoggerFactory.getLogger(Admin.class);
21
22
23 public static final String WILDCARD = "%";
24
25
26
27
28
29
30 public static void main(final String[] args) {
31 if (args.length == 0) {
32 printUsage(-1, null);
33 }
34
35 int argIndex = 0;
36 String cmd = null;
37 String arg;
38 int status = 0;
39 final ConfigFile cf = new ConfigFile("Winston.config");
40 final String driver = cf.getString("winston.driver");
41 final String url = cf.getString("winston.url");
42 final String db = cf.getString("winston.prefix");
43 final Admin admin = new Admin(driver, url, db);
44 long delay = 0;
45
46 while (argIndex < args.length && status == 0) {
47 arg = args[argIndex++];
48
49 if (arg.equals("--delay")) {
50 try {
51 arg = args[argIndex++];
52
53 delay = Integer.parseInt(arg) * 1000L;
54 } catch (final Exception e) {
55 status = 2;
56 }
57 }
58
59 else if (cmd != null || (cmd = arg).length() == 0) {
60
61 status = 2;
62 } else if (cmd.equals("--span")) {
63 admin.calculateTableSpans();
64 } else if (cmd.equals("--list")) {
65 boolean times = false;
66 if (argIndex < args.length) {
67 arg = args[argIndex++];
68 if (arg.equals("times")) {
69 times = true;
70 } else {
71 status = 2;
72 }
73 }
74 if (status == 0) {
75 admin.listChannels(times);
76 }
77 } else if (cmd.equals("--delete") || cmd.equals("--deletex")) {
78 if (argIndex < args.length) {
79 arg = args[argIndex++];
80 if (cmd.equals("--deletex")) {
81 if (admin.isChannelExpressionValid(arg)) {
82 admin.deleteChannels(arg, delay);
83 } else {
84 status = 3;
85 System.err.println(
86 "channel expresion may not have wild card for network or station (" + arg + ")");
87 }
88 } else {
89 admin.deleteChannel(arg);
90 }
91 } else {
92 status = 2;
93 }
94 } else if (cmd.equals("--purge") || cmd.equals("--purgex")) {
95 String channel = null;
96 int days = 0;
97 try {
98 arg = args[argIndex++];
99 channel = arg;
100 arg = args[argIndex++];
101 days = Integer.parseInt(arg);
102 if (days <= 0) {
103 status = 2;
104 }
105 } catch (final Exception e) {
106 status = 2;
107 }
108
109 if (status == 0) {
110 if (cmd.equals("--purgex")) {
111 admin.purgeChannels(channel, days, delay);
112 } else {
113 admin.purge(channel, days);
114 }
115 }
116 } else if (cmd.equals("--repair")) {
117 if (argIndex < args.length) {
118 final String day = args[argIndex++];
119 final String ch;
120 if (argIndex < args.length) {
121 ch = args[argIndex++];
122 } else {
123 ch = null;
124 }
125 admin.repair(day, ch);
126 } else {
127 status = 2;
128 }
129 }
130
131
132
133
134 else {
135 System.err.println("Invalid argument(" + argIndex + "): '" + arg + "'");
136 status = 1;
137 }
138 }
139
140 if (status != 0) {
141 printUsage(status, cmd);
142 }
143 }
144
145 private static void printUsage(final int status, final String cmd) {
146 if (status == 2) {
147 System.err.println("Missing or invalid command arguments for command (" + cmd + ")");
148 }
149 System.out.println(
150 "Winston Admin\n\n" + "A collection of commands for administering a Winston database.\n"
151 + "Information about connecting to the Winston database must be present\n"
152 + "in Winston.config in the current directory.\n\n" + "Usage:\n"
153 + " java gov.usgs.volcanoes.winston.db.Admin [options] command [command arguments]\n"
154 + "\nValid options:\n"
155 + " --delay seconds the delay between each channel for commands\n"
156 + " for multiple channels\n" + "\nValid commands:\n"
157 + " --list lists all channels\n"
158 + " --list times lists all channels with time span\n"
159 + " --delete channel delete the specified channel\n"
160 + " --deletex SSSS$CCC$NN[$LL] delete the specified channels where:\n"
161 + " SSSS is the station,\n"
162 + " CCC is the channel which may contain\n"
163 + " a wild card (%),\n"
164 + " SSSS is the station,\n"
165 + " NN is the network,\n"
166 + " LL is the optional location which may contain\n"
167 + " a wild card (%)\n"
168 + " --span recalculate table spans\n"
169 + " --purge channel days purge the specified channel for the\n"
170 + " specified number of days\n"
171 + " --purgex channel days purge the specified channel for the\n"
172 + " specified number of days where the channel\n"
173 + " may contain a wild card (%) anywhere\n"
174 + " --repair YYYY_MM_DD [channel] repair all tables on given day\n"
175 + " optionally, just repair the specified channel\n" +
176
177 "");
178 if (status != 0) {
179 System.exit(status);
180 }
181 }
182
183 private final Channels channels;
184
185 private final Input input;
186
187 private final WinstonDatabase winston;
188
189
190
191
192
193
194
195
196 public Admin(final String driver, final String url, final String db) {
197 this(new WinstonDatabase(driver, url, db));
198 }
199
200
201
202
203
204
205 public Admin(final WinstonDatabase w) {
206 winston = w;
207 channels = new Channels(winston);
208 input = new Input(winston);
209 }
210
211
212
213
214 public void calculateTableSpans() {
215 try {
216 final List<Channel> st = channels.getChannels();
217 for (final Iterator<Channel> it = st.iterator(); it.hasNext();) {
218 final String code = it.next().getCode();
219 System.out.print(code + "...");
220 input.calculateSpan(code);
221 System.out.println("done.");
222 }
223 } catch (final Exception e) {
224 LOGGER.error("Error during calculateTableSpans(). ({})", e.getLocalizedMessage());
225 }
226 }
227
228
229
230
231
232
233
234
235
236 public boolean checkTable(final String database, final String table) throws SQLException {
237 final ResultSet rs =
238 winston.getStatement().executeQuery("CHECK TABLE `" + table + "` FAST QUICK");
239 rs.next();
240 final String s = rs.getString("Msg_text");
241 if (s.endsWith("doesn't exist")) {
242 LOGGER.info("{} doesn't exist.", table);
243 return false;
244 }
245 return s.equals("Table is already up to date");
246 }
247
248
249
250
251
252
253 public void deleteChannel(final String ch) {
254 try {
255 winston.useRootDatabase();
256 doDeleteChannel(ch);
257 } catch (final Exception e) {
258 LOGGER.error("Error during deleteChannel().");
259 }
260 }
261
262
263
264
265
266
267
268 public void deleteChannels(final String chx, final long delay) {
269 String ch = chx;
270 try {
271 final List<String> channelList = channels.getChannelCodes(chx);
272 if (channelList == null || channelList.size() == 0) {
273 LOGGER.info("deleteChannels: no channels found ({})", chx);
274 } else {
275
276 for (int i = 0; i < channelList.size(); i++) {
277 ch = channelList.get(i);
278 if (i != 0 && delay != 0) {
279 Thread.sleep(delay);
280 }
281 doDeleteChannel(ch);
282 LOGGER.info("Deleted channel: {}", ch);
283 }
284 ch = chx;
285 }
286 } catch (final Exception e) {
287 LOGGER.error("Error during deleteChannels({})", ch);
288 }
289 }
290
291
292
293
294 public void deleteWinston() {
295 try {
296 final List<Channel> chs = channels.getChannels();
297 for (final Channel ch : chs) {
298 deleteChannel(ch.getCode());
299 }
300 winston.getStatement().execute("DROP DATABASE `" + winston.databasePrefix + "_ROOT`");
301 } catch (final Exception e) {
302 e.printStackTrace();
303 }
304 }
305
306
307
308
309
310
311
312 private void doDeleteChannel(final String ch) throws SQLException {
313 winston.getStatement().execute("DELETE FROM channels WHERE code='" + ch + "'");
314 winston.getStatement().execute("DROP DATABASE `" + winston.databasePrefix + "_" + ch + "`");
315 }
316
317
318
319
320
321
322
323
324
325
326 public boolean isChannelExpressionValid(final String chx) {
327 boolean valid = true;
328 int index;
329
330 final String[] ca = chx.split("\\$");
331 switch (ca.length) {
332 case 3:
333 if (ca[0].indexOf(WILDCARD) >= 0
334 || ((index = ca[2].indexOf(WILDCARD)) >= 0 && index <= 1)) {
335 valid = true;
336 }
337 break;
338 case 4:
339 if (ca[0].indexOf(WILDCARD) >= 0 || ca[2].indexOf(WILDCARD) >= 0) {
340 valid = true;
341 }
342 break;
343 default:
344 valid = true;
345 break;
346 }
347 return valid;
348 }
349
350
351
352
353
354
355 public void listChannels(final boolean times) {
356 final List<Channel> st = channels.getChannels();
357 for (final Channel ch : st) {
358 final String code = ch.getCode();
359 System.out.print(code);
360 if (times) {
361 System.out.print("\t" + ch.getMinTime() + "\t" + ch.getMaxTime());
362 }
363 System.out.println();
364 }
365 }
366
367
368
369
370
371
372
373 public void purge(final String channel, final int days) {
374 input.purgeTables(channel, days, this);
375 }
376
377
378
379
380
381
382
383
384 public void purgeChannels(final String chx, final int days, final long delay) {
385 String ch = chx;
386 try {
387 final List<String> channelList = channels.getChannelCodes(chx);
388 if (channelList == null || channelList.size() == 0) {
389 LOGGER.info("purgeChannels: no channels found ({})", chx);
390 } else {
391 for (int i = 0; i < channelList.size(); i++) {
392 ch = channelList.get(i);
393 if (i != 0 && delay != 0) {
394 Thread.sleep(delay);
395 }
396 purge(ch, days);
397 LOGGER.info("Purged channel: {}", ch);
398 }
399 }
400 } catch (final Exception e) {
401 LOGGER.error("Error during purgeChannels({})", ch);
402 }
403 }
404
405
406
407
408
409
410
411
412 public void repair(final String day, final String chString) {
413 if (chString == null) {
414 final List<Channel> chs = channels.getChannels();
415 for (final Channel ch : chs) {
416 repairChannel(day, ch.getCode());
417 }
418 } else {
419 repairChannel(day, chString);
420 }
421 }
422
423
424
425
426
427
428
429
430 public boolean repairChannel(final String day, final String ch) {
431 try {
432 winston.useDatabase(ch);
433 boolean fix = false;
434 final Statement st = winston.getStatement();
435
436 LOGGER.info("Checking: {} {}", ch, day);
437 ResultSet rs = st.executeQuery("CHECK TABLE `" + ch + "$$" + day + "` FAST QUICK");
438 rs.next();
439 String s = rs.getString("Msg_text");
440 if (s.endsWith("doesn't exist")) {
441 LOGGER.info("{} wave table doesn't exist.", ch);
442 return true;
443 }
444 if (!s.equals("Table is already up to date")) {
445 fix = true;
446 }
447
448 rs = st.executeQuery("CHECK TABLE `" + ch + "$$H" + day + "` FAST QUICK");
449 rs.next();
450 s = rs.getString("Msg_text");
451 if (s.endsWith("doesn't exist")) {
452 LOGGER.info("{} helicorder table doesn't exist.", ch);
453 return true;
454 }
455
456 if (!rs.getString("Msg_text").equals("Table is already up to date")) {
457 fix = true;
458 }
459
460 if (fix) {
461 LOGGER.info("Repairing: {}", ch);
462
463
464 winston.getStatement().execute("REPAIR TABLE `" + ch + "$$" + day + "`");
465 winston.getStatement().execute("REPAIR TABLE `" + ch + "$$H" + day + "`");
466 }
467 return true;
468 } catch (final Exception e) {
469 LOGGER.error("Failed to repair: {}", ch);
470 }
471 return false;
472 }
473
474
475
476
477
478
479
480
481 public boolean repairTable(final String database, final String table) {
482 try {
483 winston.useDatabase(database);
484 LOGGER.info("Checking table: {}", table);
485 boolean ct = checkTable(database, table);
486 if (ct == true) {
487 return true;
488 }
489
490 LOGGER.info("Repairing table: {}", table);
491 winston.getStatement().execute("REPAIR TABLE `" + table + "` QUICK");
492 ct = checkTable(database, table);
493 if (ct == true) {
494 return true;
495 }
496
497 LOGGER.info("Still broken, attempting further repair: {}", table);
498 winston.getStatement().execute("REPAIR TABLE `" + table + "` QUICK USE_FRM");
499 return checkTable(database, table);
500 } catch (final Exception e) {
501 LOGGER.error("Failed to repair: {}", table);
502 }
503 return false;
504 }
505 }