in src/main.c [246:507]
int main(int argc, char * const *argv) {
if (argc < 2) {
usage();
return 0;
}
const char *command = argv[1];
if (strcmp(command, "info") == 0) {
if (argc < 3) {
usage_info();
return 1;
}
return info(argc - 2, argv + 2);
} else if (strcmp(command, "get") == 0) {
if (argc < 4) {
usage_get();
return 1;
}
const char *index_filename = argv[2];
char *log_filename = sparkey_create_log_filename(index_filename);
if (log_filename == NULL) {
fprintf(stderr, "index filename must end with .spi\n");
return 1;
}
int retval = get(argv[2], log_filename, argv[3]);
free(log_filename);
return retval;
} else if (strcmp(command, "writehash") == 0) {
if (argc < 3) {
usage_writehash();
return 1;
}
const char *log_filename = argv[2];
char *index_filename = sparkey_create_index_filename(log_filename);
if (index_filename == NULL) {
fprintf(stderr, "log filename must end with .spl\n");
return 1;
}
int retval = writehash(index_filename, log_filename);
free(index_filename);
return retval;
} else if (strcmp(command, "createlog") == 0) {
opterr = 0;
optind = 2;
int opt_char;
int block_size = COMP_DEFAULT_BLOCKSIZE;
sparkey_compression_type compression_type = SPARKEY_COMPRESSION_NONE;
while ((opt_char = getopt (argc, argv, "b:c:")) != -1) {
switch (opt_char) {
case 'b':
if (sscanf(optarg, "%d", &block_size) != 1) {
fprintf(stderr, "Block size must be an integer, but was '%s'\n", optarg);
return 1;
}
if (block_size > COMP_MAX_BLOCKSIZE || block_size < COMP_MIN_BLOCKSIZE) {
fprintf(stderr, "Block size %d, not in range. Max is %d, min is %d\n",
block_size, COMP_MAX_BLOCKSIZE, COMP_MIN_BLOCKSIZE);
return 1;
}
break;
case 'c':
if (strcmp(optarg, "none") == 0) {
compression_type = SPARKEY_COMPRESSION_NONE;
} else if (strcmp(optarg, "snappy") == 0) {
compression_type = SPARKEY_COMPRESSION_SNAPPY;
} else if (strcmp(optarg, "zstd") == 0) {
compression_type = SPARKEY_COMPRESSION_ZSTD;
} else {
fprintf(stderr, "Invalid compression type: '%s'\n", optarg);
return 1;
}
break;
case '?':
if (optopt == 'b' || optopt == 'c') {
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
} else if (isprint(optopt)) {
fprintf(stderr, "Unknown option '-%c'.\n", optopt);
} else {
fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
}
return 1;
default:
fprintf(stderr, "Unknown option parsing failure\n");
return 1;
}
}
if (optind >= argc) {
usage_createlog();
return 1;
}
const char *log_filename = argv[optind];
sparkey_logwriter *writer;
assert(sparkey_logwriter_create(&writer, log_filename,
compression_type, block_size));
assert(sparkey_logwriter_close(&writer));
return 0;
} else if (strcmp(command, "appendlog") == 0) {
opterr = 0;
optind = 2;
int opt_char;
char delimiter = '\t';
while ((opt_char = getopt (argc, argv, "d:")) != -1) {
switch (opt_char) {
case 'd':
if (strlen(optarg) != 1) {
fprintf(stderr, "delimiter must be one character, but was '%s'\n", optarg);
return 1;
}
delimiter = optarg[0];
break;
case '?':
if (optopt == 'd') {
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
} else if (isprint(optopt)) {
fprintf(stderr, "Unknown option '-%c'.\n", optopt);
} else {
fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
}
return 1;
default:
fprintf(stderr, "Unknown option parsing failure\n");
return 1;
}
}
if (optind >= argc) {
usage_appendlog();
return 1;
}
const char *log_filename = argv[optind];
sparkey_logwriter *writer;
assert(sparkey_logwriter_append(&writer, log_filename));
int rc = append(writer, delimiter, stdin);
assert(sparkey_logwriter_close(&writer));
return rc;
} else if (strcmp(command, "rewrite") == 0) {
opterr = 0;
optind = 2;
int opt_char;
int block_size = -1;
sparkey_compression_type compression_type = SPARKEY_COMPRESSION_NONE;
int compression_set = 0;
while ((opt_char = getopt (argc, argv, "b:c:")) != -1) {
switch (opt_char) {
case 'b':
if (sscanf(optarg, "%d", &block_size) != 1) {
fprintf(stderr, "Block size must be an integer, but was '%s'\n", optarg);
return 1;
}
if (block_size > COMP_MAX_BLOCKSIZE || block_size < COMP_MIN_BLOCKSIZE) {
fprintf(stderr, "Block size %d, not in range. Max is %d, min is %d\n",
block_size, COMP_MAX_BLOCKSIZE, COMP_MIN_BLOCKSIZE);
return 1;
}
break;
case 'c':
compression_set = 1;
if (strcmp(optarg, "none") == 0) {
compression_type = SPARKEY_COMPRESSION_NONE;
} else if (strcmp(optarg, "snappy") == 0) {
compression_type = SPARKEY_COMPRESSION_SNAPPY;
} else if (strcmp(optarg, "zstd") == 0) {
compression_type = SPARKEY_COMPRESSION_ZSTD;
} else {
fprintf(stderr, "Invalid compression type: '%s'\n", optarg);
return 1;
}
break;
case '?':
if (optopt == 'b' || optopt == 'c') {
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
} else if (isprint(optopt)) {
fprintf(stderr, "Unknown option '-%c'.\n", optopt);
} else {
fprintf(stderr, "Unknown option character '\\x%x'.\n", optopt);
}
return 1;
default:
fprintf(stderr, "Unknown option parsing failure\n");
return 1;
}
}
if (optind + 1 >= argc) {
usage_rewrite();
return 1;
}
const char *input_index_filename = argv[optind];
const char *output_index_filename = argv[optind + 1];
if (strcmp(input_index_filename, output_index_filename) == 0) {
fprintf(stderr, "input and output must be different.\n");
return 1;
}
char *input_log_filename = sparkey_create_log_filename(input_index_filename);
if (input_log_filename == NULL) {
fprintf(stderr, "input filename must end with .spi but was '%s'\n", input_index_filename);
return 1;
}
char *output_log_filename = sparkey_create_log_filename(output_index_filename);
if (output_log_filename == NULL) {
fprintf(stderr, "output filename must end with .spi but was '%s'\n", output_index_filename);
return 1;
}
sparkey_hashreader *reader;
assert(sparkey_hash_open(&reader, input_index_filename, input_log_filename));
sparkey_logreader *logreader = sparkey_hash_getreader(reader);
if (!compression_set) {
compression_type = sparkey_logreader_get_compression_type(logreader);
}
if (block_size == -1) {
block_size = sparkey_logreader_get_compression_blocksize(logreader);
}
// TODO: skip rewrite if compression type and block size are unchanged, and there is no garbage in the log
sparkey_logwriter *writer;
assert(sparkey_logwriter_create(&writer, output_log_filename, compression_type, block_size));
sparkey_logiter *iter;
assert(sparkey_logiter_create(&iter, logreader));
uint8_t *keybuf = malloc(sparkey_logreader_maxkeylen(logreader));
uint8_t *valuebuf = malloc(sparkey_logreader_maxvaluelen(logreader));
while (1) {
assert(sparkey_logiter_next(iter, logreader));
if (sparkey_logiter_state(iter) != SPARKEY_ITER_ACTIVE) {
break;
}
uint64_t wanted_keylen = sparkey_logiter_keylen(iter);
uint64_t actual_keylen;
assert(sparkey_logiter_fill_key(iter, logreader, wanted_keylen, keybuf, &actual_keylen));
uint64_t wanted_valuelen = sparkey_logiter_valuelen(iter);
uint64_t actual_valuelen;
assert(sparkey_logiter_fill_value(iter, logreader, wanted_valuelen, valuebuf, &actual_valuelen));
assert(sparkey_logwriter_put(writer, wanted_keylen, keybuf, wanted_valuelen, valuebuf));
}
free(keybuf);
free(valuebuf);
sparkey_logiter_close(&iter);
assert(sparkey_logwriter_close(&writer));
sparkey_hash_close(&reader);
writehash(output_index_filename, output_log_filename);
return 0;
} else if (strcmp(command, "help") == 0 || strcmp(command, "--help") == 0 || strcmp(command, "-h") == 0) {
usage();
return 0;
} else {
fprintf(stderr, "Unknown command: %s\n", command);
return 1;
}
}