#ifdef __FreeBSD__
#define _WITH_GETLINE
#endif
#include <stdio.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include "arttree_structures.h"
#include <stdarg.h>
#define APPNAME "examine_arttree"
#define SRCVERSION "0.1"
size_t art_node_sizes[art_node_types] = {
sizeof(art_node4),
sizeof(art_node16),
sizeof(art_node48),
sizeof(art_node256),
sizeof(art_leaf),
sizeof(art_node_u),
sizeof(art_node),
sizeof(art_tree_root),
sizeof(var_string),
};
char *art_node_names[art_node_types] = {
"art_node4",
"art_node16",
"art_node48",
"art_node256",
"art_leaf",
"art_node_u",
"art_node",
"art_tree_root",
"var_string"
};
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0 },
};
struct command {
const char *name;
const char *brief;
int (*func)(char *, struct pmem_context *, int, char *[]);
void (*help)(char *);
};
#define COMMANDS_NUMBER (sizeof(commands) / sizeof(commands[0]))
static void print_help(char *appname);
static void print_usage(char *appname);
static void print_version(char *appname);
static int quit_func(char *appname, struct pmem_context *ctx,
int argc, char *argv[]);
static void quit_help(char *appname);
static int set_root_func(char *appname, struct pmem_context *ctx,
int argc, char *argv[]);
static void set_root_help(char *appname);
static int help_func(char *appname, struct pmem_context *ctx,
int argc, char *argv[]);
static void help_help(char *appname);
static struct command *get_command(char *cmd_str);
static int ctx_init(struct pmem_context *ctx, char *filename);
static int arttree_structures_func(char *appname, struct pmem_context *ctx,
int ac, char *av[]);
static void arttree_structures_help(char *appname);
static int arttree_info_func(char *appname, struct pmem_context *ctx,
int ac, char *av[]);
static void arttree_info_help(char *appname);
extern int arttree_examine_func();
extern void arttree_examine_help();
extern int arttree_search_func();
extern void arttree_search_help();
void outv_err(const char *fmt, ...);
void outv_err_vargs(const char *fmt, va_list ap);
static struct command commands[] = {
{
.name = "art_structures",
.brief = "print information about ART structures",
.func = arttree_structures_func,
.help = arttree_structures_help,
},
{
.name = "info",
.brief = "print information and statistics"
"about a art tree pool",
.func = arttree_info_func,
.help = arttree_info_help,
},
{
.name = "examine",
.brief = "examine data structures from an ART tree",
.func = arttree_examine_func,
.help = arttree_examine_help,
},
{
.name = "search",
.brief = "search for a key in the ART tree",
.func = arttree_search_func,
.help = arttree_search_help,
},
{
.name = "set_root",
.brief = "define offset of root of art tree",
.func = set_root_func,
.help = set_root_help,
},
{
.name = "help",
.brief = "print help text about a command",
.func = help_func,
.help = help_help,
},
{
.name = "quit",
.brief = "quit arttree structure examiner",
.func = quit_func,
.help = quit_help,
},
};
static struct pmem_context ctx;
void
outv_err(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
outv_err_vargs(fmt, ap);
va_end(ap);
}
void
outv_err_vargs(const char *fmt, va_list ap)
{
fprintf(stderr, "error: ");
vfprintf(stderr, fmt, ap);
if (!strchr(fmt, '\n'))
fprintf(stderr, "\n");
}
static void
print_usage(char *appname)
{
printf("usage: %s [--help] <pmem file> <command> [<args>]\n", appname);
}
static void
print_version(char *appname)
{
printf("%s %s\n", appname, SRCVERSION);
}
static void
print_help(char *appname)
{
print_usage(appname);
print_version(appname);
printf("\n");
printf("Options:\n");
printf(" -h, --help display this help and exit\n");
printf("\n");
printf("The available commands are:\n");
int i;
for (i = 0; i < COMMANDS_NUMBER; i++)
printf("%s\t- %s\n", commands[i].name, commands[i].brief);
printf("\n");
}
static void
set_root_help(char *appname)
{
printf("Usage: set_root <offset>\n");
printf(" define the offset of the art tree root\n");
}
static int
set_root_func(char *appname, struct pmem_context *ctx, int argc, char *argv[])
{
int retval = 0;
uint64_t root_offset;
if (argc == 2) {
root_offset = strtol(argv[1], NULL, 0);
ctx->art_tree_root_offset = root_offset;
} else {
set_root_help(appname);
retval = 1;
}
return retval;
}
static void
quit_help(char *appname)
{
printf("Usage: quit\n");
printf(" terminate arttree structure examiner\n");
}
static int
quit_func(char *appname, struct pmem_context *ctx, int argc, char *argv[])
{
printf("\n");
exit(0);
return 0;
}
static void
help_help(char *appname)
{
printf("Usage: %s help <command>\n", appname);
}
static int
help_func(char *appname, struct pmem_context *ctx, int argc, char *argv[])
{
if (argc > 1) {
char *cmd_str = argv[1];
struct command *cmdp = get_command(cmd_str);
if (cmdp && cmdp->help) {
cmdp->help(appname);
return 0;
} else {
outv_err("No help text for '%s' command\n", cmd_str);
return -1;
}
} else {
print_help(appname);
return -1;
}
}
static const char *arttree_structures_help_str =
"Show information about known ART tree structures\n"
;
static void
arttree_structures_help(char *appname)
{
printf("%s %s\n", appname, arttree_structures_help_str);
}
static int
arttree_structures_func(char *appname, struct pmem_context *ctx,
int ac, char *av[])
{
(void) appname;
(void) ac;
(void) av;
printf(
"typedef struct pmemoid {\n"
" uint64_t pool_uuid_lo;\n"
" uint64_t off;\n"
"} PMEMoid;\n");
printf("sizeof(PMEMoid) = %ld\n\n\n", sizeof(PMEMoid));
printf(
"struct _art_node_u; typedef struct _art_node_u art_node_u;\n"
"struct _art_node_u { \n"
" uint8_t art_node_type; \n"
" uint8_t art_node_tag; \n"
"};\n");
printf("sizeof(art_node_u) = %ld\n\n\n", sizeof(art_node_u));
printf(
"struct _art_node; typedef struct _art_node art_node;\n"
"struct _art_node {\n"
" uint8_t type;\n"
" uint8_t num_children;\n"
" uint32_t partial_len;\n"
" unsigned char partial[10];\n"
"};\n");
printf("sizeof(art_node) = %ld\n\n\n", sizeof(art_node));
printf(
"typedef uint8_t _toid_art_node_toid_type_num[8];\n");
printf("sizeof(_toid_art_node_toid_type_num[8]) = %ld\n\n\n",
sizeof(_toid_art_node_toid_type_num[8]));
printf(
"union _toid_art_node_u_toid {\n"
" PMEMoid oid;\n"
" art_node_u *_type;\n"
" _toid_art_node_u_toid_type_num *_type_num;\n"
"};\n");
printf("sizeof(union _toid_art_node_u_toid) = %ld\n\n\n",
sizeof(union _toid_art_node_u_toid));
printf(
"typedef uint8_t _toid_art_node_toid_type_num[8];\n");
printf("sizeof(_toid_art_node_toid_type_num[8]) = %ld\n\n\n",
sizeof(_toid_art_node_toid_type_num[8]));
printf(
"union _toid_art_node_toid {\n"
" PMEMoid oid; \n"
" art_node *_type; \n"
" _toid_art_node_toid_type_num *_type_num;\n"
"};\n");
printf("sizeof(union _toid_art_node_toid) = %ld\n\n\n",
sizeof(union _toid_art_node_toid));
printf(
"struct _art_node4; typedef struct _art_node4 art_node4;\n"
"struct _art_node4 {\n"
" art_node n;\n"
" unsigned char keys[4];\n"
" union _toid_art_node_u_toid children[4];\n"
"};\n");
printf("sizeof(art_node4) = %ld\n\n\n", sizeof(art_node4));
printf(
"struct _art_node16; typedef struct _art_node16 art_node16;\n"
"struct _art_node16 {\n"
" art_node n;\n"
" unsigned char keys[16];\n"
" union _toid_art_node_u_toid children[16];\n"
"};\n");
printf("sizeof(art_node16) = %ld\n\n\n", sizeof(art_node16));
printf(
"struct _art_node48; typedef struct _art_node48 art_node48;\n"
"struct _art_node48 {\n"
" art_node n;\n"
" unsigned char keys[256];\n"
" union _toid_art_node_u_toid children[48];\n"
"};\n");
printf("sizeof(art_node48) = %ld\n\n\n", sizeof(art_node48));
printf(
"struct _art_node256; typedef struct _art_node256 art_node256;\n"
"struct _art_node256 {\n"
" art_ndoe n;\n"
" union _toid_art_node_u_toid children[256];\n"
"};\n");
printf("sizeof(art_node256) = %ld\n\n\n", sizeof(art_node256));
printf(
"struct _art_leaf; typedef struct _art_leaf art_leaf;\n"
"struct _art_leaf {\n"
" union _toid_var_string_toid value;\n"
" union _toid_var_string_toid key;\n"
"};\n");
printf("sizeof(art_leaf) = %ld\n\n\n", sizeof(art_leaf));
return 0;
}
static const char *arttree_info_help_str =
"Show information about known ART tree structures\n"
;
static void
arttree_info_help(char *appname)
{
printf("%s %s\n", appname, arttree_info_help_str);
}
static int
arttree_info_func(char *appname, struct pmem_context *ctx, int ac, char *av[])
{
printf("%s: %s not yet implemented\n", appname, __FUNCTION__);
return 0;
}
static struct command *
get_command(char *cmd_str)
{
int i;
if (cmd_str == NULL) {
return NULL;
}
for (i = 0; i < COMMANDS_NUMBER; i++) {
if (strcmp(cmd_str, commands[i].name) == 0)
return &commands[i];
}
return NULL;
}
static int
ctx_init(struct pmem_context *ctx, char *filename)
{
int errors = 0;
if (filename == NULL)
errors++;
if (ctx == NULL)
errors++;
if (!errors) {
ctx->filename = strdup(filename);
assert(ctx->filename != NULL);
ctx->fd = -1;
ctx->art_tree_root_offset = 0;
if (access(ctx->filename, F_OK) == 0) {
ctx->fd = open(ctx->filename, O_RDONLY);
} else {
errors++;
}
ctx->sys_pagesize = sysconf(_SC_PAGESIZE);
}
return errors;
}
int
main(int ac, char *av[])
{
int opt;
int option_index;
int ret = 0;
size_t len;
ssize_t read;
char *cmd_str;
char *args[20];
int nargs;
char *line;
struct command *cmdp = NULL;
while ((opt = getopt_long(ac, av, "h",
long_options, &option_index)) != -1) {
switch (opt) {
case 'h':
print_help(APPNAME);
return 0;
default:
print_usage(APPNAME);
return -1;
}
}
if (optind >= ac) {
fprintf(stderr, "ERROR: missing arguments\n");
print_usage(APPNAME);
return -1;
}
ctx_init(&ctx, av[optind]);
if (optind + 1 < ac) {
cmd_str = av[optind + 1];
cmdp = get_command(cmd_str);
if (cmdp != NULL) {
ret = cmdp->func(APPNAME, &ctx, ac - 2, av + 2);
}
} else {
line = NULL;
printf("\n> ");
while ((read = getline(&line, &len, stdin)) != -1) {
if (line[read - 1] == '\n') {
line[read - 1] = '\0';
}
args[0] = strtok(line, " ");
cmdp = get_command(args[0]);
if (cmdp == NULL) {
printf("[%s]: command not supported\n",
args[0] ? args[0] : "NULL");
printf("\n> ");
continue;
}
nargs = 1;
while (1) {
args[nargs] = strtok(NULL, " ");
if (args[nargs] == NULL) {
break;
}
nargs++;
}
ret = cmdp->func(APPNAME, &ctx, nargs, args);
printf("\n> ");
}
if (line != NULL) {
free(line);
}
}
return ret;
}