aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/eventcnv.c15
-rw-r--r--mps/code/eventsql.c422
2 files changed, 260 insertions, 177 deletions
diff --git a/mps/code/eventcnv.c b/mps/code/eventcnv.c
index fcd569add74..42c84c376df 100644
--- a/mps/code/eventcnv.c
+++ b/mps/code/eventcnv.c
@@ -499,7 +499,7 @@ static void readLog(EventProc proc)
499 499
500 case EventLabelCode: 500 case EventLabelCode:
501 switch (style) { 501 switch (style) {
502 case '\0': case 'C': 502 case '\0':
503 { 503 {
504 const char *sym = LabelText(proc, event->Label.f1); 504 const char *sym = LabelText(proc, event->Label.f1);
505 printf(style == '\0' ? 505 printf(style == '\0' ?
@@ -507,12 +507,10 @@ static void readLog(EventProc proc)
507 ", %"PRIuLONGEST", ", 507 ", %"PRIuLONGEST", ",
508 (ulongest_t)event->Label.f0); 508 (ulongest_t)event->Label.f0);
509 if (sym != NULL) { 509 if (sym != NULL) {
510 printStr(sym, (style == 'C')); 510 printStr(sym, 0);
511 } else { 511 } else {
512 printf(style == '\0' ? 512 printf("sym %05"PRIXLONGEST ,
513 "sym %05"PRIXLONGEST : 513 (ulongest_t)event->Label.f1);
514 "sym %"PRIXLONGEST"\"",
515 (ulongest_t)event->Label.f1);
516 } 514 }
517 } 515 }
518 break; 516 break;
@@ -521,6 +519,11 @@ static void readLog(EventProc proc)
521 (ulongest_t)event->Label.f0, 519 (ulongest_t)event->Label.f0,
522 (ulongest_t)event->Label.f1); 520 (ulongest_t)event->Label.f1);
523 break; 521 break;
522 case 'C':
523 printf(", %"PRIuLONGEST", %"PRIuLONGEST,
524 (ulongest_t)event->Label.f0,
525 (ulongest_t)event->Label.f1);
526 break;
524 } 527 }
525 break; 528 break;
526 529
diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c
index d4401192942..9b069ac65e6 100644
--- a/mps/code/eventsql.c
+++ b/mps/code/eventsql.c
@@ -1,30 +1,38 @@
1/* eventsql.c: event log to SQLite importer 1/* eventsql.c: event log to SQLite importer.
2 *
3 * $Id*
4 *
2 * Copyright (c) 2012 Ravenbrook Limited. See end of file for license. 5 * Copyright (c) 2012 Ravenbrook Limited. See end of file for license.
3 * 6 *
4 * This is a command-line tool that imports events from a binary 7 * This is a command-line tool that imports events from a text-format
5 * format telemetry output file from the MPS into a SQLite database 8 * MPS telemetry file into a SQLite database file.
6 * file.
7 *
8 * The default MPS library will write a telemetry stream to a file called
9 * "mpsio.log" when the environment variable MPS_TELEMETRY_CONTROL is set
10 * to an integer whose bits select event kinds. For example:
11 * 9 *
12 * MPS_TELEMETRY_CONTROL=7 amcss 10 * The default MPS library will write a binary-format telemetry file.
11 * The binary-format file can be converted into a text-format file
12 * using the eventcnv program with the -SC -v options. For
13 * binary-format compatibility, eventcnv has to be run on the same
14 * platform as the MPS.
13 * 15 *
14 * will run the amcss test program and emit a file with event kinds 0, 1, 2. 16 * These ASCII text-format files have one line per event, and can be
15 * The file can then be imported into a SQLite database with this command: 17 * manipulated by various splendid systems in the usual Unix way. This
18 * eventsql program is one such.
16 * 19 *
17 * eventsql 20 * Note that eventsql can read streams that come from an MPS running
18 * 21 * on another platform. This is another reason why we use the
19 * Note that the eventsql program can only read streams that come from an 22 * intermediate text-format file, rather than reading the
20 * MPS compiled on the same platform. 23 * binary-format file directly: you can run the MPS and then eventcnv
24 * on the target platform, then optionally analyse the resulting text
25 * file on some other machine.
21 * 26 *
22 * Each event type gets its own table in the database. These tables 27 * Each event type gets its own table in the database. These tables
23 * are created from the definitions in eventdef.h if they don't 28 * are created from the definitions in eventdef.h if they don't
24 * already exist. Each event becomes a single row in the appropriate 29 * already exist. Each event becomes a single row in the appropriate
25 * table, which has a column for each event parameter, a time column 30 * table, which has a column for each event parameter, a time column
26 * for the event time field, and a log_serial column to identify the 31 * for the event time field, and a log_serial column to identify the
27 * log file. 32 * log file. Because the database schema depends on the event
33 * definitions in eventdef.h, eventsql has to be compiled using the
34 * same event header files as those used to compile the MPS and
35 * eventcnv which generated and processed the telemetry output.
28 * 36 *
29 * The program also creates three other tables: two 'glue' tables 37 * The program also creates three other tables: two 'glue' tables
30 * containing event metadata - event_kind (one row per kind) and 38 * containing event metadata - event_kind (one row per kind) and
@@ -45,19 +53,19 @@
45 * progress (one dot is 100k events). 53 * progress (one dot is 100k events).
46 * 54 *
47 * -t (test): Run unit tests on parts of eventsql. There aren't many 55 * -t (test): Run unit tests on parts of eventsql. There aren't many
48 * of these. 56 * of these. TODO: write more unit tests.
49 * 57 *
50 * -f (force): Import the events to SQL even if the SQL database 58 * -f (force): Import the events to SQL even if the SQL database
51 * already includes a record of importing this event log file (matched by 59 * already includes a record of importing a matching log file.
52 * size, modtime, and filesystem ID.
53 * 60 *
54 * -r (rebuild): Drop the glue tables from SQL, which will force them 61 * -r (rebuild): Drop the glue tables from SQL, which will force them
55 * to be recreated. Important if you change event types or kinds in 62 * to be recreated. Important if you change event types or kinds in
56 * eventdef.h. 63 * eventdef.h.
57 * 64 *
58 * -l <logfile>: Import events from the named logfile. If not 65 * -l <logfile>: Import events from the named logfile. Defaults to
59 * specified, eventsql will use the MPS_TELEMETRY_FILENAME environment 66 * stdin. If the specified file (matched by size and modtime) has
60 * variable, and default to mpsio.log. 67 * previously been imported to the same database, it will not be
68 * imported again unless -f is specified.
61 * 69 *
62 * -d <database>: Import events to the named database file. If not 70 * -d <database>: Import events to the named database file. If not
63 * specified, eventsql will use the MPS_EVENT_DATABASE environment 71 * specified, eventsql will use the MPS_EVENT_DATABASE environment
@@ -66,9 +74,10 @@
66 * $Id$ 74 * $Id$
67 */ 75 */
68 76
77#include "misc.h"
69#include "config.h" 78#include "config.h"
70#include "eventdef.h" 79#include "eventdef.h"
71#include "eventpro.h" 80#include "eventcom.h"
72 81
73#include <stdio.h> 82#include <stdio.h>
74#include <stdlib.h> 83#include <stdlib.h>
@@ -79,9 +88,6 @@
79#define DATABASE_NAME_ENVAR "MPS_EVENT_DATABASE" 88#define DATABASE_NAME_ENVAR "MPS_EVENT_DATABASE"
80#define DEFAULT_DATABASE_NAME "mpsevent.db" 89#define DEFAULT_DATABASE_NAME "mpsevent.db"
81 90
82#define TELEMETRY_FILENAME_ENVAR "MPS_TELEMETRY_FILENAME"
83#define DEFAULT_TELEMETRY_FILENAME "mpsio.log"
84
85/* we output rows of dots. One dot per SMALL_TICK events, 91/* we output rows of dots. One dot per SMALL_TICK events,
86 * BIG_TICK dots per row. */ 92 * BIG_TICK dots per row. */
87 93
@@ -231,7 +237,7 @@ static sqlite3 *openDatabase(void)
231 if (res != SQLITE_OK) 237 if (res != SQLITE_OK)
232 sqlite_error(res, db, "Opening %s failed", databaseName); 238 sqlite_error(res, db, "Opening %s failed", databaseName);
233 239
234 log(LOG_ALWAYS, "Writing to %s.",databaseName); 240 log(LOG_OFTEN, "Writing to %s.",databaseName);
235 241
236 return db; 242 return db;
237} 243}
@@ -243,7 +249,7 @@ static void closeDatabase(sqlite3 *db)
243 int res = sqlite3_close(db); 249 int res = sqlite3_close(db);
244 if (res != SQLITE_OK) 250 if (res != SQLITE_OK)
245 sqlite_error(res, db, "Closing database failed"); 251 sqlite_error(res, db, "Closing database failed");
246 log(LOG_ALWAYS, "Closed %s.", databaseName); 252 log(LOG_SOMETIMES, "Closed %s.", databaseName);
247} 253}
248 254
249/* We need to be able to test for the existence of a table. The 255/* We need to be able to test for the existence of a table. The
@@ -268,7 +274,7 @@ static int tableExists(sqlite3* db, const char *tableName)
268 if (!sql) 274 if (!sql)
269 error("Out of memory."); 275 error("Out of memory.");
270 sprintf(sql, format, tableName); 276 sprintf(sql, format, tableName);
271 log(LOG_RARELY, "Testing for existence of table '%s' with SQL: %s", tableName, sql); 277 log(LOG_SELDOM, "Testing for existence of table '%s' with SQL: %s", tableName, sql);
272 res = sqlite3_exec(db, 278 res = sqlite3_exec(db,
273 sql, 279 sql,
274 NULL, /* put in a callback here if we really want to know the number of rows */ 280 NULL, /* put in a callback here if we really want to know the number of rows */
@@ -278,12 +284,12 @@ static int tableExists(sqlite3* db, const char *tableName)
278 284
279 switch(res) { 285 switch(res) {
280 case SQLITE_OK: 286 case SQLITE_OK:
281 log(LOG_RARELY, "Table '%s' exists.", tableName); 287 log(LOG_SELDOM, "Table '%s' exists.", tableName);
282 288
283 return 1; /* table exists */ 289 return 1; /* table exists */
284 break; 290 break;
285 case SQLITE_ERROR: 291 case SQLITE_ERROR:
286 log(LOG_RARELY, "Table '%s' does not exist.", tableName); 292 log(LOG_SELDOM, "Table '%s' does not exist.", tableName);
287 return 0; /* table does not exist; we can 293 return 0; /* table does not exist; we can
288 probably do a better test for this case. */ 294 probably do a better test for this case. */
289 break; 295 break;
@@ -344,6 +350,7 @@ static void runStatement(sqlite3 *db,
344 const char *description) 350 const char *description)
345{ 351{
346 int res; 352 int res;
353 log(LOG_SELDOM, "%s: %s", description, sql);
347 res = sqlite3_exec(db, 354 res = sqlite3_exec(db,
348 sql, 355 sql,
349 NULL, /* No callback */ 356 NULL, /* No callback */
@@ -366,70 +373,74 @@ static unsigned long logSerial = 0;
366static void registerLogFile(sqlite3 *db, 373static void registerLogFile(sqlite3 *db,
367 const char *filename) 374 const char *filename)
368{ 375{
369 struct stat st;
370 sqlite3_stmt *statement; 376 sqlite3_stmt *statement;
371 int res; 377 int res;
372 const unsigned char *name; 378 const unsigned char *name;
373 unsigned long completed; 379 unsigned long completed;
374 380 unsigned long long file_size;
375 res = stat(filename, &st); 381 unsigned long long file_modtime;
376 if (res != 0) 382
377 error("Couldn't stat() %s", filename); 383 if (filename) {
378 384 struct stat st;
379 statement = prepareStatement(db, 385 res = stat(filename, &st);
380 "SELECT name, serial, completed FROM event_log" 386 if (res != 0)
381 " WHERE file_id = ? AND size = ? AND modtime = ?"); 387 error("Couldn't stat() %s", filename);
382 res = sqlite3_bind_int64(statement, 1, st.st_ino); 388 file_size = st.st_size;
383 if (res != SQLITE_OK) 389 file_modtime = st.st_mtime;
384 sqlite_error(res, db, "event_log bind of file_id failed."); 390
385 res = sqlite3_bind_int64(statement, 2, st.st_size); 391 statement = prepareStatement(db,
386 if (res != SQLITE_OK) 392 "SELECT name, serial, completed FROM event_log"
387 sqlite_error(res, db, "event_log bind of size failed."); 393 " WHERE size = ? AND modtime = ?");
388 res = sqlite3_bind_int64(statement, 3, st.st_mtime); 394 res = sqlite3_bind_int64(statement, 1, file_size);
389 if (res != SQLITE_OK) 395 if (res != SQLITE_OK)
390 sqlite_error(res, db, "event_log bind of modtime failed."); 396 sqlite_error(res, db, "event_log bind of size failed.");
391 397 res = sqlite3_bind_int64(statement, 2, file_modtime);
392 res = sqlite3_step(statement); 398 if (res != SQLITE_OK)
393 switch(res) { 399 sqlite_error(res, db, "event_log bind of modtime failed.");
394 case SQLITE_DONE: 400 res = sqlite3_step(statement);
395 log(LOG_SOMETIMES, "No log file matching '%s' found in database.", filename); 401 switch(res) {
396 break; 402 case SQLITE_DONE:
397 case SQLITE_ROW: 403 log(LOG_SOMETIMES, "No log file matching '%s' found in database.", filename);
398 name = sqlite3_column_text(statement, 0); 404 break;
399 logSerial = sqlite3_column_int(statement, 1); 405 case SQLITE_ROW:
400 completed = sqlite3_column_int(statement, 2); 406 name = sqlite3_column_text(statement, 0);
401 log(LOG_ALWAYS, "Log file matching '%s' already in event_log, named \"%s\" (serial %lu, completed %lu).", 407 logSerial = sqlite3_column_int(statement, 1);
402 filename, name, logSerial, completed); 408 completed = sqlite3_column_int(statement, 2);
403 if (!force) { 409 log(force ? LOG_OFTEN : LOG_ALWAYS, "Log file matching '%s' already in event_log, named \"%s\" (serial %lu, completed %lu).",
404 log(LOG_ALWAYS, "Exiting. Specify -f to force events into SQL anyway."); 410 filename, name, logSerial, completed);
405 exit(0); 411 if (force) {
412 log(LOG_OFTEN, "Continuing anyway because -f specified.");
413 } else {
414 log(LOG_ALWAYS, "Exiting. Specify -f to force events into SQL anyway.");
415 exit(0);
416 }
417 break;
418 default:
419 sqlite_error(res, db, "select from event_log failed.");
406 } 420 }
407 log(LOG_ALWAYS, "Continuing anyway because -f specified."); 421 finalizeStatement(db, statement);
408 break; 422 } else { /* stdin */
409 default: 423 filename = "<stdin>";
410 sqlite_error(res, db, "select from event_log failed."); 424 file_size = 0;
425 file_modtime = 0;
411 } 426 }
412 finalizeStatement(db, statement);
413 statement = prepareStatement(db, 427 statement = prepareStatement(db,
414 "INSERT into event_log (name, file_id, size, modtime, completed)" 428 "INSERT into event_log (name, size, modtime, completed)"
415 " VALUES (?, ?, ?, ?, 0)"); 429 " VALUES (?, ?, ?, 0)");
416 res = sqlite3_bind_text(statement, 1, filename, -1, SQLITE_STATIC); 430 res = sqlite3_bind_text(statement, 1, filename, -1, SQLITE_STATIC);
417 if (res != SQLITE_OK) 431 if (res != SQLITE_OK)
418 sqlite_error(res, db, "event_log insert bind of name failed."); 432 sqlite_error(res, db, "event_log insert bind of name failed.");
419 res = sqlite3_bind_int64(statement, 2, st.st_ino); 433 res = sqlite3_bind_int64(statement, 2, file_size);
420 if (res != SQLITE_OK)
421 sqlite_error(res, db, "event_log insert bind of file_id failed.");
422 res = sqlite3_bind_int64(statement, 3, st.st_size);
423 if (res != SQLITE_OK) 434 if (res != SQLITE_OK)
424 sqlite_error(res, db, "event_log insert bind of size failed."); 435 sqlite_error(res, db, "event_log insert bind of size failed.");
425 res = sqlite3_bind_int64(statement, 4, st.st_mtime); 436 res = sqlite3_bind_int64(statement, 3, file_modtime);
426 if (res != SQLITE_OK) 437 if (res != SQLITE_OK)
427 sqlite_error(res, db, "event_log insert bind of modtime failed."); 438 sqlite_error(res, db, "event_log insert bind of modtime failed.");
428 res = sqlite3_step(statement); 439 res = sqlite3_step(statement);
429 if (res != SQLITE_DONE) 440 if (res != SQLITE_DONE)
430 sqlite_error(res, db, "insert into event_log failed."); 441 sqlite_error(res, db, "insert into event_log failed.");
431 logSerial = sqlite3_last_insert_rowid(db); 442 logSerial = sqlite3_last_insert_rowid(db);
432 log(LOG_SOMETIMES, "Log file added to event_log with serial %lu", 443 log(LOG_SOMETIMES, "Log file %s added to event_log with serial %lu",
433 filename, logSerial); 444 filename, logSerial);
434 finalizeStatement(db, statement); 445 finalizeStatement(db, statement);
435} 446}
@@ -451,7 +462,7 @@ static void logFileCompleted(sqlite3 *db,
451 res = sqlite3_step(statement); 462 res = sqlite3_step(statement);
452 if (res != SQLITE_DONE) 463 if (res != SQLITE_DONE)
453 sqlite_error(res, db, "insert into event_log failed."); 464 sqlite_error(res, db, "insert into event_log failed.");
454 log(LOG_OFTEN, "Marked in event_log: %lu events", completed); 465 log(LOG_SOMETIMES, "Marked in event_log: %lu events", completed);
455 finalizeStatement(db, statement); 466 finalizeStatement(db, statement);
456} 467}
457 468
@@ -488,7 +499,6 @@ const char *createStatements[] = {
488 " FOREIGN KEY (kind) REFERENCES event_kind(enum));", 499 " FOREIGN KEY (kind) REFERENCES event_kind(enum));",
489 500
490 "CREATE TABLE IF NOT EXISTS event_log (name TEXT," 501 "CREATE TABLE IF NOT EXISTS event_log (name TEXT,"
491 " file_id INTEGER,"
492 " size INTEGER," 502 " size INTEGER,"
493 " modtime INTEGER," 503 " modtime INTEGER,"
494 " completed INTEGER," 504 " completed INTEGER,"
@@ -502,9 +512,9 @@ EVENT_LIST(EVENT_TABLE_CREATE, X)
502static void makeTables(sqlite3 *db) 512static void makeTables(sqlite3 *db)
503{ 513{
504 int i; 514 int i;
515 log(LOG_SOMETIMES, "Creating tables.");
505 516
506 for (i=0; i < (sizeof(createStatements)/sizeof(createStatements[0])); ++i) { 517 for (i=0; i < (sizeof(createStatements)/sizeof(createStatements[0])); ++i) {
507 log(LOG_SOMETIMES, "Creating tables. SQL command: %s", createStatements[i]);
508 runStatement(db, createStatements[i], "Table creation"); 518 runStatement(db, createStatements[i], "Table creation");
509 } 519 }
510} 520}
@@ -581,8 +591,8 @@ static void dropGlueTables(sqlite3 *db)
581static void fillGlueTables(sqlite3 *db) 591static void fillGlueTables(sqlite3 *db)
582{ 592{
583 int i; 593 int i;
584 Res res;
585 sqlite3_stmt *statement; 594 sqlite3_stmt *statement;
595 int res;
586 596
587 statement = prepareStatement(db, 597 statement = prepareStatement(db,
588 "INSERT OR IGNORE INTO event_kind (name, description, enum)" 598 "INSERT OR IGNORE INTO event_kind (name, description, enum)"
@@ -622,61 +632,100 @@ static void fillGlueTables(sqlite3 *db)
622#define EVENT_TYPE_FINALIZE_STATEMENT(X, name, code, always, kind) \ 632#define EVENT_TYPE_FINALIZE_STATEMENT(X, name, code, always, kind) \
623 finalizeStatement(db, stmt_##name); 633 finalizeStatement(db, stmt_##name);
624 634
625#define EVENT_PARAM_BIND_INTEGER(name, index, sort, ident) \ 635#define EVENT_PARAM_BIND_A bind_int
626 res = sqlite3_bind_int64(statement, index+1, (unsigned long) event->name.f##index); 636#define EVENT_PARAM_BIND_P bind_int
627 637#define EVENT_PARAM_BIND_U bind_int
628#define EVENT_PARAM_BIND_REAL(name, index, sort, ident) \ 638#define EVENT_PARAM_BIND_W bind_int
629 res = sqlite3_bind_double(statement, index+1, event->name.f##index); 639#define EVENT_PARAM_BIND_D bind_real
630 640#define EVENT_PARAM_BIND_S bind_text
631#define EVENT_PARAM_BIND_TEXT(name, index, sort, ident) \ 641#define EVENT_PARAM_BIND_B bind_int
632 res = sqlite3_bind_text(statement, index+1, event->name.f##index, -1, SQLITE_STATIC);
633
634#define EVENT_PARAM_BIND_A EVENT_PARAM_BIND_INTEGER
635#define EVENT_PARAM_BIND_P EVENT_PARAM_BIND_INTEGER
636#define EVENT_PARAM_BIND_U EVENT_PARAM_BIND_INTEGER
637#define EVENT_PARAM_BIND_W EVENT_PARAM_BIND_INTEGER
638#define EVENT_PARAM_BIND_D EVENT_PARAM_BIND_REAL
639#define EVENT_PARAM_BIND_S EVENT_PARAM_BIND_TEXT
640#define EVENT_PARAM_BIND_B EVENT_PARAM_BIND_INTEGER
641 642
642#define EVENT_PARAM_BIND(name, index, sort, ident) \ 643#define EVENT_PARAM_BIND(X, index, sort, ident) \
643 EVENT_PARAM_BIND_##sort (name, index, sort, ident) \ 644 p = EVENT_PARAM_BIND_##sort (db, statement, eventCount, index+1, p); \
644 if (res != SQLITE_OK) \
645 sqlite_error(res, db, "Event " #name " bind of ident " #ident "failed."); \
646 last_index = index+1; 645 last_index = index+1;
647 646
648
649#define EVENT_TYPE_WRITE_SQL(X, name, code, always, kind) \ 647#define EVENT_TYPE_WRITE_SQL(X, name, code, always, kind) \
650 case code: \ 648 case code: \
651 { \ 649 statement = stmt_##name; \
652 sqlite3_stmt *statement = stmt_##name; \
653 int last_index = 0; \
654 int res; \
655 /* bind all the parameters of this particular event with macro magic. */ \ 650 /* bind all the parameters of this particular event with macro magic. */ \
656 EVENT_##name##_PARAMS(EVENT_PARAM_BIND, name) \ 651 EVENT_##name##_PARAMS(EVENT_PARAM_BIND, X) \
657 /* bind the fields we store for every event */ \ 652 break;
658 res = sqlite3_bind_int64(statement, last_index+1, logSerial); \ 653
659 if (res != SQLITE_OK) \ 654static char *bind_int(sqlite3 *db, sqlite3_stmt *stmt, unsigned long long count, int index, char *p)
660 sqlite_error(res, db, "Event " #name " bind of log_serial failed."); \ 655{
661 res = sqlite3_bind_int64(statement, last_index+2, event->any.clock); \ 656 char *q;
662 if (res != SQLITE_OK) \ 657 long long val;
663 sqlite_error(res, db, "Event " #name " bind of clock failed."); \ 658 int res;
664 res = sqlite3_step(statement); \ 659
665 if (res != SQLITE_DONE) \ 660 if ((p[0] != ',') || (p[1] != ' '))
666 sqlite_error(res, db, "insert of event \"" #name "\" failed."); \ 661 error("event %llu field %d not preceded by \", \": %s",
667 res = sqlite3_reset(statement); \ 662 count, index, p);
668 if (res != SQLITE_OK) \ 663
669 sqlite_error(res, db, "Couldn't reset insert statement for \"" #name "\"."); \ 664 p += 2;
670 } \ 665 val = strtoll(p, &q, 0);
671 break; 666 if (q == p)
667 error("event %llu field %d not an integer: %s",
668 count, index, p);
669
670 res = sqlite3_bind_int64(stmt, index, val);
671 if (res != SQLITE_OK)
672 sqlite_error(res, db, "event %llu field %d bind failed", count, index);
673 return q;
674}
675
676static char *bind_real(sqlite3 *db, sqlite3_stmt *stmt, unsigned long long count, int index, char *p)
677{
678 char *q;
679 double val;
680 int res;
681
682 if ((p[0] != ',') || (p[1] != ' '))
683 error("event %llu field %d not preceded by \", \": %s",
684 count, index, p);
685
686 p += 2;
687 val = strtod(p, &q);
688 if (q == p)
689 error("event %llu field %d not a floating-point value: %s",
690 count, index, p);
691
692 res = sqlite3_bind_double(stmt, index, val);
693 if (res != SQLITE_OK)
694 sqlite_error(res, db, "event %llu field %d bind failed", count, index);
695 return q;
696}
697
698static char *bind_text(sqlite3 *db, sqlite3_stmt *stmt, unsigned long long count, int index, char *p)
699{
700 char *q;
701 int res;
702
703 if ((p[0] != ',') || (p[1] != ' ') || (p[2] != '"'))
704 error("event %llu string field %d not preceded by \", \\\"\": %s",
705 count, index, p);
672 706
673/* readLog -- read and parse log 707 p += 3;
708 q = p;
709 while((*q != '\n') && (*q != '\0')) {
710 ++ q;
711 }
712 if ((q == p) || (q[-1] != '"'))
713 error("event %llu string field %d has no closing quote mark.",
714 count, index);
715
716 res = sqlite3_bind_text(stmt, index, p, q-p-1, SQLITE_STATIC);
717 if (res != SQLITE_OK)
718 sqlite_error(res, db, "event %llu field %d bind failed", count, index);
719 return q;
720}
721
722/* readLog -- read and parse log. Returns the number of events written.
674 */ 723 */
675 724
676static void readLog(EventProc proc, 725static unsigned long long readLog(FILE *input,
677 sqlite3 *db) 726 sqlite3 *db)
678{ 727{
679 size_t eventCount = 0; 728 unsigned long long eventCount = 0;
680 729
681 /* declare statements for every event type */ 730 /* declare statements for every event type */
682 EVENT_LIST(EVENT_TYPE_DECLARE_STATEMENT, X); 731 EVENT_LIST(EVENT_TYPE_DECLARE_STATEMENT, X);
@@ -687,28 +736,70 @@ static void readLog(EventProc proc,
687 runStatement(db, "BEGIN", "Transaction start"); 736 runStatement(db, "BEGIN", "Transaction start");
688 737
689 while (TRUE) { /* loop for each event */ 738 while (TRUE) { /* loop for each event */
690 Event event; 739 char line[1024];
691 EventCode code; 740 char *p;
692 Res res; 741 char *q;
693 742 int last_index=0;
694 /* Read and parse event. */ 743 sqlite3_stmt *statement;
695 res = EventRead(&event, proc); 744 int res;
696 if (res == ResFAIL) break; /* eof */ 745 unsigned long long clock;
697 if (res != ResOK) error("Truncated log"); 746 int code;
698 code = event->any.code; 747
699 748 p = fgets(line, 1024, input);
749 if (!p) {
750 if (feof(input))
751 break;
752 else
753 error("Couldn't read line after event %llu", eventCount);
754 }
755
756 eventCount++;
757
758 clock = strtoll(p, &q, 16);
759 if (q == p)
760 error("event %llu clock field not a hex integer: %s",
761 eventCount, p);
762
763 if ((q[0] != ',') || (q[1] != ' '))
764 error("event %llu code field not preceded by \", \": %s",
765 eventCount, q);
766
767 p = q + 2;
768
769 code = strtol(p, &q, 0);
770 if (q == p)
771 error("event %llu code field %d not an integer: %s",
772 eventCount, index, p);
773 p = q;
700 /* Write event to SQLite. */ 774 /* Write event to SQLite. */
701 switch (code) { 775 switch (code) {
776 /* this macro sets statement and last_index */
702 EVENT_LIST(EVENT_TYPE_WRITE_SQL, X); 777 EVENT_LIST(EVENT_TYPE_WRITE_SQL, X);
778 default:
779 error("Event %llu has Unknown event code %d", eventCount, code);
703 } 780 }
704 EventDestroy(proc, event); 781 /* bind the fields we store for every event */ \
705 eventCount++; 782 res = sqlite3_bind_int64(statement, last_index+1, logSerial);
783 if (res != SQLITE_OK)
784 sqlite_error(res, db, "Event %llu bind of log_serial failed.", eventCount);
785 res = sqlite3_bind_int64(statement, last_index+2, clock);
786 if (res != SQLITE_OK)
787 sqlite_error(res, db, "Event %llu bind of clock failed.", eventCount);
788 res = sqlite3_step(statement);
789 if (res != SQLITE_DONE)
790 sqlite_error(res, db, "insert of event %llu failed.", eventCount);
791 res = sqlite3_reset(statement);
792 if (res != SQLITE_OK)
793 sqlite_error(res, db, "Couldn't reset insert statement of event %llu", eventCount);
794
706 if (verbosity > LOG_ALWAYS) { 795 if (verbosity > LOG_ALWAYS) {
707 if ((eventCount % SMALL_TICK) == 0) { 796 if ((eventCount % SMALL_TICK) == 0) {
708 printf("."); 797 printf(".");
709 fflush(stdout); 798 fflush(stdout);
710 if (((eventCount / SMALL_TICK) % BIG_TICK) == 0) { 799 if (((eventCount / SMALL_TICK) % BIG_TICK) == 0) {
711 log(LOG_OFTEN, "%lu events.", (unsigned long)eventCount); 800 printf("\n");
801 fflush(stdout);
802 log(LOG_SOMETIMES, "%lu events.", (unsigned long)eventCount);
712 } 803 }
713 } 804 }
714 } 805 }
@@ -718,64 +809,48 @@ static void readLog(EventProc proc,
718 fflush(stdout); 809 fflush(stdout);
719 } 810 }
720 runStatement(db, "COMMIT", "Transaction finish"); 811 runStatement(db, "COMMIT", "Transaction finish");
721
722 log(LOG_ALWAYS, "Wrote %lu events to SQL.", (unsigned long)eventCount);
723 logFileCompleted(db, eventCount); 812 logFileCompleted(db, eventCount);
724 813
725 /* finalize all the statements */ 814 /* finalize all the statements */
726 EVENT_LIST(EVENT_TYPE_FINALIZE_STATEMENT, X); 815 EVENT_LIST(EVENT_TYPE_FINALIZE_STATEMENT, X);
727}
728 816
729static Res logReader(void *file, void *p, size_t len) 817 return eventCount;
730{
731 size_t n;
732
733 n = fread(p, 1, len, (FILE *)file);
734 return (n < len) ? (feof((FILE *)file) ? ResFAIL : ResIO) : ResOK;
735} 818}
736 819
737static FILE *openLog(sqlite3 *db) 820static FILE *openLog(sqlite3 *db)
738{ 821{
739 FILE *input; 822 FILE *input;
740 823
824 registerLogFile(db, logFileName);
741 if (!logFileName) { 825 if (!logFileName) {
742 logFileName = getenv(TELEMETRY_FILENAME_ENVAR); 826 input = stdin;
743 if(logFileName == NULL) 827 logFileName = "<stdin>";
744 logFileName = DEFAULT_TELEMETRY_FILENAME; 828 } else {
829 input = fopen(logFileName, "r");
830 if (input == NULL)
831 error("unable to open %s", logFileName);
745 } 832 }
746 833
747 registerLogFile(db, logFileName); 834 log(LOG_OFTEN, "Reading %s.", logFileName ? logFileName : "standard input");
748 input = fopen(logFileName, "rb");
749
750 if (input == NULL)
751 error("unable to open %s", logFileName);
752
753 log(LOG_ALWAYS, "Reading %s.", logFileName);
754 835
755 return input; 836 return input;
756} 837}
757 838
758static void writeEventsToSQL(sqlite3 *db) 839static unsigned long long writeEventsToSQL(sqlite3 *db)
759{ 840{
760 Res res;
761 EventProc proc;
762 FILE *input; 841 FILE *input;
763 842 unsigned long long count;
764 input = openLog(db); 843 input = openLog(db);
765 res = EventProcCreate(&proc, logReader, (void *)input); 844 count = readLog(input, db);
766 if (res != ResOK)
767 error("Can't init EventProc module: error %d.", res);
768
769 readLog(proc, db);
770
771 EventProcDestroy(proc);
772 (void)fclose(input); 845 (void)fclose(input);
846 return count;
773} 847}
774 848
775 849
776int main(int argc, char *argv[]) 850int main(int argc, char *argv[])
777{ 851{
778 sqlite3 *db; 852 sqlite3 *db;
853 unsigned long long count;
779 854
780 parseArgs(argc, argv); 855 parseArgs(argc, argv);
781 856
@@ -785,7 +860,12 @@ int main(int argc, char *argv[])
785 } 860 }
786 makeTables(db); 861 makeTables(db);
787 fillGlueTables(db); 862 fillGlueTables(db);
788 writeEventsToSQL(db); 863 count = writeEventsToSQL(db);
864 log(LOG_ALWAYS, "Imported %llu events from %s to %s, serial %lu.",
865 (unsigned long)count,
866 logFileName,
867 databaseName,
868 logSerial);
789 869
790 if (runTests) { 870 if (runTests) {
791 /* TODO: more unit tests in here */ 871 /* TODO: more unit tests in here */