コード例 #1
0
ファイル: table_tests.c プロジェクト: emiddleton/sky
int test_sky_table_open() {
    struct tagbstring lock_file_path = bsStatic("tmp/.skylock");
    struct tagbstring data_file_path = bsStatic("tmp/0/data");
    struct tagbstring header_file_path = bsStatic("tmp/0/header");
    cleantmp();
    
    int rc;
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    
    // Open table.
    rc = sky_table_open(table);
    mu_assert_int_equals(rc, 0);
    mu_assert(sky_file_exists(&lock_file_path), "");
    mu_assert(sky_file_exists(&data_file_path), "");
    mu_assert(sky_file_exists(&header_file_path), "");
    
    // Close table.
    rc = sky_table_close(table);
    mu_assert_int_equals(rc, 0);
    mu_assert(!sky_file_exists(&lock_file_path), "");
    mu_assert(sky_file_exists(&data_file_path), "");
    mu_assert(sky_file_exists(&header_file_path), "");

    sky_table_free(table);
    return 0;
}
コード例 #2
0
ファイル: add_event_0_tests.c プロジェクト: gitaccount2/sky
int test() {
    pthread_t thread;
    importtmp_n("tests/functional/fixtures/add_event/0/data.json", 4);
    start_server(1, &thread);
    send_msg("tests/functional/fixtures/add_event/0/input");
    pthread_join(thread, NULL);

    mu_assert_msg("tests/functional/fixtures/add_event/0/output");

    void *data;
    size_t data_length;
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);
    sky_tablet_get_path(table->tablets[2], 10, &data, &data_length);
    mu_assert_mem(data, 
        "\x03\xe8\x03\x00\x00\x00\x00\x00\x00\x05\x00\x1f\x00\x00\x00\xff"
        "\xa6\x7a\x7a\x7a\x7a\x7a\x7a\xfe\x0a\x01\xa3\x78\x79\x7a\x02\xd1"
        "\x00\xc8\x03\xcb\x40\x59\x0c\xcc\xcc\xcc\xcc\xcd\x04\xc3\x01\x00"
        "\x00\x10\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x20\x00\x00\x00"
        "\x00\x00\x02\x00\x01\x00\x00\x30\x00\x00\x00\x00\x00\x03\x00",
        data_length
    );
    sky_table_free(table);
    free(data);
    return 0;
}
コード例 #3
0
ファイル: importer.c プロジェクト: dasfaha/sky
int sky_importer_process_event(sky_importer *importer, bstring source,
                               jsmntok_t *tokens, uint32_t *index)
{
    int rc;
    check(importer != NULL, "Importer required");
    check(source != NULL, "Source required");
    check(tokens != NULL, "Tokens required");
    check(index != NULL, "Token index required");

    jsmntok_t *event_token = &tokens[*index];
    (*index)++;

    // Open table if it hasn't been already.
    if(!importer->table->opened) {
        check(sky_table_open(importer->table) == 0, "Unable to open table");
    }

    // Create the event object.
    sky_event *event = sky_event_create(0, 0, 0); check_mem(event);
        
    // Process over child tokens.
    int32_t i;
    for(i=0; i<(event_token->size/2); i++) {
        jsmntok_t *token = &tokens[*index];
        (*index)++;
        
        if(sky_importer_tokstr_equal(source, token, "timestamp")) {
            bstring timestamp = sky_importer_token_parse_bstring(source, &tokens[(*index)++]);
            rc = sky_timestamp_parse(timestamp, &event->timestamp);
            check(rc == 0, "Unable to parse timestamp");
            bdestroy(timestamp);
        }
        else if(sky_importer_tokstr_equal(source, token, "objectId")) {
            event->object_id = (sky_object_id_t)sky_importer_token_parse_int(source, &tokens[(*index)++]);
        }
        else if(sky_importer_tokstr_equal(source, token, "action")) {
            sky_action *action = NULL;
            bstring action_name = sky_importer_token_parse_bstring(source, &tokens[(*index)++]);
            rc = sky_action_file_find_action_by_name(importer->table->action_file, action_name, &action);
            check(rc == 0, "Unable to find action: %s", bdata(action_name));
            event->action_id = action->id;
        }
        else if(sky_importer_tokstr_equal(source, token, "data")) {
            rc = sky_importer_process_event_data(importer, event, source, tokens, index);
            check(rc == 0, "Unable to import event data");
        }
        else {
            sentinel("Invalid token at char %d", tokens[*index].start);
        }
    }
    
    // Add event.
    rc = sky_table_add_event(importer->table, event);
    check(rc == 0, "Unable to add event");
    
    return 0;

error:
    return -1;
}
コード例 #4
0
ファイル: sky_lua_tests.c プロジェクト: fxstein/sky
int test_sky_lua_generate_header() {
    importtmp("tests/fixtures/sky_lua/0/data.json");
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);

    struct tagbstring source = bsStatic(
        "function aggregate(event)\n"
        "  label = event:first_name() .. ' ' .. event:last_name()\n"
        "  return event.x + event.y\n"
        "end\n"
    );
    bstring event_decl = NULL;
    bstring event_metatype = NULL;
    bstring init_descriptor_func = NULL;
    int rc = sky_lua_generate_event_info(&source, table->property_file, &event_decl, &event_metatype, &init_descriptor_func);
    mu_assert_int_equals(rc, 0);
    mu_assert_bstring(event_decl,
        "typedef struct {\n"
        "  int64_t ts;\n"
        "  uint32_t timestamp;\n"
        "  uint16_t action_id;\n"
        "  sky_string_t _first_name;\n"
        "  sky_string_t _last_name;\n"
        "  int32_t x;\n"
        "  int32_t y;\n"
        "} sky_lua_event_t;"
    );
    mu_assert_bstring(event_metatype,
        "ffi.metatype('sky_lua_event_t', {\n"
        "  __index = {\n"
        "    first_name = function(event) return ffi.string(event._first_name.data, event._first_name.length) end,\n"
        "    last_name = function(event) return ffi.string(event._last_name.data, event._last_name.length) end,\n"
        "    x = function(event) return event.x end,\n"
        "    y = function(event) return event.y end,\n"
        "  }\n"
        "})\n"
    );
    mu_assert_bstring(init_descriptor_func,
        "function sky_init_descriptor(_descriptor)\n"
        "  descriptor = ffi.cast('sky_data_descriptor_t*', _descriptor)\n"
        "  descriptor:set_data_sz(ffi.sizeof('sky_lua_event_t'));\n"
        "  descriptor:set_ts_offset(ffi.offsetof('sky_lua_event_t', 'ts'));\n"
        "  descriptor:set_timestamp_offset(ffi.offsetof('sky_lua_event_t', 'timestamp'));\n"
        "  descriptor:set_action_id_offset(ffi.offsetof('sky_lua_event_t', 'action_id'));\n"
        "  descriptor:set_property(4, ffi.offsetof('sky_lua_event_t', '_first_name'), 1);\n"
        "  descriptor:set_property(5, ffi.offsetof('sky_lua_event_t', '_last_name'), 1);\n"
        "  descriptor:set_property(2, ffi.offsetof('sky_lua_event_t', 'x'), 2);\n"
        "  descriptor:set_property(3, ffi.offsetof('sky_lua_event_t', 'y'), 2);\n"
        "end\n"
    );
    bdestroy(event_decl);
    bdestroy(event_metatype);
    bdestroy(init_descriptor_func);
    sky_table_free(table);
    return 0;
}
コード例 #5
0
ファイル: sky_lua_tests.c プロジェクト: fxstein/sky
int test_sky_aggregate() {
    importtmp("tests/fixtures/sky_lua/1/data.json");
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);
    sky_data_descriptor *descriptor = sky_data_descriptor_create();

    // Initialize the path iterator.
    sky_path_iterator iterator;
    sky_path_iterator_init(&iterator);
    iterator.cursor.data_descriptor = descriptor;
    sky_path_iterator_set_tablet(&iterator, table->tablets[0]);

    struct tagbstring source = bsStatic(
        "function aggregate(cursor, data)\n"
        "  data.path_count = (data.path_count or 0) + 1\n"
        "  while cursor:next() do\n"
        "    data.event_count = (data.event_count or 0) + 1\n"
        "    data.z = (data.z or 0) + cursor.event.x + cursor.event.y\n"
        "  end\n"
        "end\n"
    );
    lua_State *L = NULL;
    int rc = sky_lua_initscript_with_table(&source, table, descriptor, &L);
    mu_assert_int_equals(rc, 0);

    // Allocate data.
    mu_assert_int_equals(descriptor->data_sz, 24);
    iterator.cursor.data = calloc(1, descriptor->data_sz);

    // Start benchmark.
    struct timeval tv;
    gettimeofday(&tv, NULL);
    int64_t t0 = (tv.tv_sec*1000) + (tv.tv_usec/1000);

    // Call sky_aggregate() function.
    uint32_t i;
    for(i=0; i<1; i++) {
        //sky_path_iterator_set_tablet(&iterator, table->tablets[0]);
        lua_getglobal(L, "sky_aggregate");
        lua_pushlightuserdata(L, &iterator);
        lua_call(L, 1, 0);
    }

    // End benchmark.
    gettimeofday(&tv, NULL);
    int64_t t1 = (tv.tv_sec*1000) + (tv.tv_usec/1000);
    printf("[lua] t=%.3fs\n", ((float)(t1-t0))/1000);

    sky_path_iterator_uninit(&iterator);
    sky_table_free(table);
    free(iterator.cursor.data);
    return 0;
}
コード例 #6
0
ファイル: importer.c プロジェクト: emiddleton/sky
int sky_importer_process_property(sky_importer *importer, bstring source,
                                  jsmntok_t *tokens, uint32_t *index)
{
    int rc;
    assert(importer != NULL);
    assert(source != NULL);
    assert(tokens != NULL);
    assert(index != NULL);

    jsmntok_t *property_token = &tokens[*index];
    (*index)++;
    
    // Create the property object.
    sky_property *property = sky_property_create(); check_mem(property);
    
    // Process over child tokens.
    int32_t i;
    for(i=0; i<(property_token->size/2); i++) {
        jsmntok_t *token = &tokens[*index];
        (*index)++;
        
        if(sky_importer_tokstr_equal(source, token, "type")) {
            bstring type = sky_importer_token_parse_bstring(source, &tokens[*index]);
            property->type = biseqcstr(type, "action") == 1 ? SKY_PROPERTY_TYPE_ACTION : SKY_PROPERTY_TYPE_OBJECT;
            bdestroy(type);
        }
        else if(sky_importer_tokstr_equal(source, token, "dataType")) {
            bstring data_type_str = sky_importer_token_parse_bstring(source, &tokens[*index]);
            property->data_type = sky_data_type_to_enum(data_type_str);
            bdestroy(data_type_str);
        }
        else if(sky_importer_tokstr_equal(source, token, "name")) {
            property->name = sky_importer_token_parse_bstring(source, &tokens[*index]);
        }
        else {
            sentinel("Invalid token at char %d", tokens[*index].start);
        }
        
        (*index)++;
    }
    
    // Add property.
    if(!importer->table->opened) {
        check(sky_table_open(importer->table) == 0, "Unable to open table");
    }
    rc = sky_property_file_add_property(importer->table->property_file, property);
    check(rc == 0, "Unable to add property: %s", bdata(property->name));
    
    return 0;

error:
    return -1;
}
コード例 #7
0
ファイル: server.c プロジェクト: gitaccount2/sky
// Opens a table and attaches it to the server.
//
// server - The server.
// name   - The table name.
// path   - The table path.
// ret    - A pointer to where the table reference should be returned.
//
// Returns 0 if successful, otherwise returns -1.
int sky_server_open_table(sky_server *server, bstring name, bstring path,
                          sky_table **ret)
{
    int rc;
    sky_table *table = NULL;
    assert(server != NULL);
    assert(ret != NULL);
    check(blength(path) > 0, "Table path required");
    
    // Initialize return values.
    *ret = NULL;
    
    // Only open the table if it exists already.
    if(sky_file_exists(path)) {
        // Create the table.
        table = sky_table_create(); check_mem(table);
        table->name = bstrcpy(name); check_mem(table->name);
        rc = sky_table_set_path(table, path);
        check(rc == 0, "Unable to set table path");

        // Open the table.
        rc = sky_table_open(table);
        check(rc == 0, "Unable to open table");
    
        // Append the table to the list of open tables.
        server->table_count++;
        server->tables = realloc(server->tables, server->table_count * sizeof(*server->tables));
        check_mem(server->tables);
        server->tables[server->table_count-1] = table;

        // Open servlets for the table's tablets.
        rc = sky_server_create_servlets(server, table);
        check(rc == 0, "Unable to create servlets for table");

        // Return table.
        *ret = table;
    }

    return 0;

error:
    sky_table_free(table);
    if(ret) *ret = NULL;
    return -1;
}
コード例 #8
0
int test_sky_get_property_message_process() {
    loadtmp("tests/fixtures/get_property_message/1/table");
    sky_server *server = sky_server_create(NULL);
    sky_message_header *header = sky_message_header_create();
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);
    
    FILE *input = fopen("tests/fixtures/get_property_message/1/input", "r");
    FILE *output = fopen("tmp/output", "w");
    int rc = sky_get_property_message_process(server, header, table, input, output);
    mu_assert_int_equals(rc, 0);
    mu_assert_file("tmp/output", "tests/fixtures/get_property_message/1/output");

    sky_table_free(table);
    sky_message_header_free(header);
    sky_server_free(server);
    return 0;
}
コード例 #9
0
ファイル: importer.c プロジェクト: emiddleton/sky
int sky_importer_process_action(sky_importer *importer, bstring source,
                                jsmntok_t *tokens, uint32_t *index)
{
    int rc;
    assert(importer != NULL);
    assert(source != NULL);
    assert(tokens != NULL);
    assert(index != NULL);

    jsmntok_t *action_token = &tokens[*index];
    (*index)++;
    
    // Create the action object.
    sky_action *action = sky_action_create(); check_mem(action);
    
    // Process over child tokens.
    int32_t i;
    for(i=0; i<(action_token->size/2); i++) {
        jsmntok_t *token = &tokens[*index];
        (*index)++;
        
        if(sky_importer_tokstr_equal(source, token, "name")) {
            action->name = sky_importer_token_parse_bstring(source, &tokens[*index]);
        }
        else {
            sentinel("Invalid token at char %d", tokens[*index].start);
        }
        (*index)++;
    }
    
    // Add action.
    if(!importer->table->opened) {
        check(sky_table_open(importer->table) == 0, "Unable to open table");
    }
    rc = sky_action_file_add_action(importer->table->action_file, action);
    check(rc == 0, "Unable to add action: %s", bdata(action->name));
    
    return 0;

error:
    return -1;
}
コード例 #10
0
ファイル: eadd_message_tests.c プロジェクト: gitaccount2/sky
int test_sky_add_event_message_worker_map() {
    importtmp("tests/fixtures/add_event_message/1/import.json");
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    table->default_tablet_count = 1;
    sky_table_open(table);

    struct tagbstring XYZ_STR = bsStatic("xyz");
    sky_add_event_message *message = sky_add_event_message_create();
    message->event = sky_event_create(10, 1000L, 20);
    message->event->data_count = 4;
    message->event->data = calloc(message->event->data_count, sizeof(*message->event->data));
    message->event->data[0] = sky_event_data_create_string(1, &XYZ_STR);
    message->event->data[1] = sky_event_data_create_int(2, 200);
    message->event->data[2] = sky_event_data_create_double(3, 100.2);
    message->event->data[3] = sky_event_data_create_boolean(4, true);
    sky_worker *worker = sky_worker_create();
    worker->data = (void*)message;

    void *null = NULL;
    int rc = sky_add_event_message_worker_map(worker, table->tablets[0], &null);
    mu_assert_int_equals(rc, 0);

    void *data;
    size_t data_length;
    sky_tablet_get_path(table->tablets[0], 10, &data, &data_length);
    mu_assert_int_equals(rc, 0);
    mu_assert_mem(
        data, 
        "\x03\xE8\x03\x00\x00\x00\x00\x00\x00\x14\x00\x15\x00\x00\x00\x01"
        "\xA3\x78\x79\x7A\x02\xD1\x00\xC8\x03\xCB\x40\x59\x0C\xCC\xCC\xCC"
        "\xCC\xCD\x04\xC3",
        data_length
    );

    free(data);
    sky_add_event_message_free(message);
    sky_worker_free(worker);
    sky_table_free(table);
    return 0;
}
コード例 #11
0
ファイル: sky_lua_tests.c プロジェクト: fxstein/sky
int test_sky_lua_initscript_with_table() {
    int rc;
    importtmp("tests/fixtures/sky_lua/0/data.json");
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);
    sky_data_descriptor *descriptor = sky_data_descriptor_create();

    sky_lua_event_0_t lua_event = {0, 0, 1, 20, 30};

    struct tagbstring source = bsStatic(
        "function aggregate(_event)\n"
        "  event = ffi.cast('sky_lua_event_t*', _event)\n"
        "  return event.x + event.y\n"
        "end\n"
    );
    lua_State *L = NULL;
    rc = sky_lua_initscript_with_table(&source, table, descriptor, &L);
    mu_assert_int_equals(rc, 0);
    mu_assert_int_equals(descriptor->timestamp_descriptor.ts_offset, 0);
    mu_assert_int_equals(descriptor->timestamp_descriptor.timestamp_offset, 8);
    mu_assert_int_equals(descriptor->action_descriptor.offset, 12);
    mu_assert_int_equals(descriptor->property_zero_descriptor[1].offset, 0);
    mu_assert_int_equals(descriptor->property_zero_descriptor[2].offset, (int)offsetof(sky_lua_event_0_t, x));
    mu_assert_int_equals(descriptor->property_zero_descriptor[3].offset, (int)offsetof(sky_lua_event_0_t, y));
    mu_assert_int_equals(descriptor->property_zero_descriptor[4].offset, 0);

    // Call aggregate() function with the event pointer.
    lua_getglobal(L, "aggregate");
    lua_pushlightuserdata(L, &lua_event);
    lua_call(L, 1, 1);
    mu_assert_int_equals(rc, 0);
    mu_assert_long_equals(lua_tointeger(L, -1), 50L);
    
    sky_table_free(table);
    return 0;
}
コード例 #12
0
ファイル: peach_message_tests.c プロジェクト: dasfaha/sky
int test_sky_peach_message_process() {
    importtmp("tests/fixtures/peach_message/1/import.json");
    sky_table *table = sky_table_create();
    table->path = bfromcstr("tmp");
    sky_table_open(table);
    
    // NOTE: The table contains two properties: foo (String) and this_is_a_really...(Int)
    sky_peach_message *message = sky_peach_message_create();
    message->query = bfromcstr(
        "[Hashable(\"id\")]\n"
        "[Serializable]\n"
        "class Result {\n"
        "  public Int id;\n"
        "  public Int count;\n"
        "  public Int objectTotal;\n"
        "  public Int actionTotal;\n"
        "}\n"
        "Cursor cursor = path.events();\n"
        "for each (Event event in cursor) {\n"
        "  String dynamic_prop2 = event.this_is_a_really_long_property_name_woohoo;\n"
        "  Result item = data.get(event.actionId);\n"
        "  item.count = item.count + 1;\n"
        "  item.objectTotal = item.objectTotal + event.object_prop;\n"
        "  item.actionTotal = item.actionTotal + event.action_prop;\n"
        "}\n"
        "return;"
    );

    FILE *output = fopen("tmp/output", "w");
    mu_assert(sky_peach_message_process(message, table, output) == 0, "");
    fclose(output);
    mu_assert_file("tmp/output", "tests/fixtures/peach_message/1/output");

    sky_peach_message_free(message);
    sky_table_free(table);
    return 0;
}
コード例 #13
0
ファイル: sky_bench.c プロジェクト: dasfaha/sky
// Executes the benchmark to count the number of times an action occurred
// using the QIP language.
//
// options - A list of options to use.
void benchmark_count_with_qip(Options *options)
{
    int rc;
    uint32_t path_count = 0;
    
    // Initialize the query.
    qip_ast_node *type_ref, *var_decl;
    uint32_t arg_count = 2;
    qip_ast_node *args[arg_count];
    
    // Path arg.
    struct tagbstring path_str = bsStatic("path");
    type_ref = qip_ast_type_ref_create_cstr("Path");
    var_decl = qip_ast_var_decl_create(type_ref, &path_str, NULL);
    args[0] = qip_ast_farg_create(var_decl);
    
    // Map arg.
    struct tagbstring data_str = bsStatic("data");
    type_ref = qip_ast_type_ref_create_cstr("Map");
    qip_ast_type_ref_add_subtype(type_ref, qip_ast_type_ref_create_cstr("Int"));
    qip_ast_type_ref_add_subtype(type_ref, qip_ast_type_ref_create_cstr("Result"));
    var_decl = qip_ast_var_decl_create(type_ref, &data_str, NULL);
    args[1] = qip_ast_farg_create(var_decl);

    // Initialize query.
    struct tagbstring query = bsStatic(
        "[Hashable(\"id\")]\n"
        "class Result {\n"
        "  public Int id;\n"
        "  public Int count;\n"
        "}\n"
        "Cursor cursor = path.events();\n"
        "for each (Event event in cursor) {\n"
        "  Result item = data.get(event.actionId);\n"
        "  item.count = item.count + 1;\n"
        "}\n"
        "return;"
    );
    struct tagbstring module_name = bsStatic("qip");
    struct tagbstring core_class_path = bsStatic("lib/core");
    struct tagbstring sky_class_path = bsStatic("lib/sky");
    qip_compiler *compiler = qip_compiler_create();
    qip_compiler_add_class_path(compiler, &core_class_path);
    qip_compiler_add_class_path(compiler, &sky_class_path);
    qip_module *module = qip_module_create(&module_name, compiler);
    rc = qip_compiler_compile(compiler, module, &query, args, arg_count);
    check(rc == 0, "Unable to compile");
    if(module->error_count > 0) fprintf(stderr, "Parse error [line %d] %s\n", module->errors[0]->line_no, bdata(module->errors[0]->message));
    check(module->error_count == 0, "Compile error");
    qip_compiler_free(compiler);

    // Retrieve pointer to function.
    sky_qip_path_map_func process_path = NULL;
    rc = qip_module_get_main_function(module, (void*)(&process_path));
    check(rc == 0, "Unable to retrieve main function");

    // Initialize table.
    sky_table *table = sky_table_create(); check_mem(table);
    rc = sky_table_set_path(table, options->path);
    check(rc == 0, "Unable to set path on table");
    
    // Open table
    rc = sky_table_open(table);
    check(rc == 0, "Unable to open table");

    // Loop for desired number of iterations.
    int i;
    for(i=0; i<options->iterations; i++) {
        sky_path_iterator iterator;
        sky_path_iterator_init(&iterator);

        // Attach data file.
        rc = sky_path_iterator_set_data_file(&iterator, table->data_file);
        check(rc == 0, "Unable to initialze path iterator");

        // Initialize QIP args.
        sky_qip_path *path = sky_qip_path_create();
        qip_map *map = qip_map_create();
        
        // Iterate over each path.
        while(!iterator.eof) {
            // Retrieve the path pointer.
            rc = sky_path_iterator_get_ptr(&iterator, &path->path_ptr);
            check(rc == 0, "Unable to retrieve the path iterator pointer");
        
            // Execute query.
            process_path(path, map);

            // Move to next path.
            rc = sky_path_iterator_next(&iterator);
            check(rc == 0, "Unable to find next path");

            path_count++;
        }
        
        // Clean up iteration.
        qip_map_free(map);
    }
    
    // Clean up
    rc = sky_table_close(table);
    check(rc == 0, "Unable to close table");
    sky_table_free(table);

    // Show stats.
    printf("Total paths processed: %d\n", path_count);
    
    return;
    
error:
    sky_table_free(table);
}
コード例 #14
0
ファイル: sky_bench.c プロジェクト: dasfaha/sky
// Executes the benchmark over the database to compute step counts in order to
// generate a directed acyclic graph (DAG).
//
// options - A list of options to use.
void benchmark_dag(Options *options)
{
    int rc;
    sky_event *event = NULL;
    uint32_t event_count = 0;
    int32_t action_count = 100;     // TODO: Retrieve action count from actions file.
    
    // Initialize table.
    sky_table *table = sky_table_create(); check_mem(table);
    rc = sky_table_set_path(table, options->path);
    check(rc == 0, "Unable to set path on table");
    
    // Open table
    rc = sky_table_open(table);
    check(rc == 0, "Unable to open table");

    // Loop for desired number of iterations.
    int i;
    for(i=0; i<options->iterations; i++) {
        sky_path_iterator iterator;
        sky_path_iterator_init(&iterator);
        
        // Attach data file.
        rc = sky_path_iterator_set_data_file(&iterator, table->data_file);
        check(rc == 0, "Unable to initialze path iterator");
        
        // Create a square matrix of structs.
        Step *steps = calloc(action_count*action_count, sizeof(Step));

        // Iterate over each path.
        while(!iterator.eof) {
            sky_action_id_t action_id, prev_action_id;

            // Retrieve the path pointer.
            void *path_ptr;
            rc = sky_path_iterator_get_ptr(&iterator, &path_ptr);
            check(rc == 0, "Unable to retrieve the path iterator pointer");
        
            // Initialize the cursor.
            sky_cursor cursor;
            sky_cursor_init(&cursor);
            rc = sky_cursor_set_path(&cursor, path_ptr);
            check(rc == 0, "Unable to set cursor path");

            // Increment total event count.
            event_count++;
            
            // Initialize the previous action.
            rc = sky_cursor_get_action_id(&cursor, &prev_action_id);
            check(rc == 0, "Unable to retrieve first action");

            // Find next event.
            rc = sky_cursor_next(&cursor);
            check(rc == 0, "Unable to find next event");

            // Loop over each event in the path.
            while(!cursor.eof) {
                // Increment total event count.
                event_count++;

                // Retrieve action.
                rc = sky_cursor_get_action_id(&cursor, &action_id);
                check(rc == 0, "Unable to retrieve first action");

                // Aggregate step information.
                int32_t index = ((prev_action_id-1)*action_count) + (action_id-1);
                steps[index].count++;

                // Assign current action as previous action.
                prev_action_id = action_id;

                // Find next event.
                rc = sky_cursor_next(&cursor);
                check(rc == 0, "Unable to find next event");
            }
            
            rc = sky_path_iterator_next(&iterator);
            check(rc == 0, "Unable to find next path");
        }
        
        // Show DAG data.
        //int x;
        //int total=0;
        //for(x=0; x<action_count*action_count; x++) {
        //    printf("%06d %d\n", x, steps[x].count);
        //    total += steps[x].count;
        //}
        //printf("total: %d\n", total);
    }
    
    // Clean up
    rc = sky_table_close(table);
    check(rc == 0, "Unable to close table");
    sky_table_free(table);

    // Show stats.
    printf("Total events processed: %d\n", event_count);
    
    return;
    
error:
    sky_event_free(event);
    sky_table_free(table);
}