Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ $ ./fkvs-cli -h 127.0.0.1 -p 5995 --non-interactive
|---|---|---|
| `PING` | `PING` or `PING value` | Test connectivity; returns `PONG` or echoes the value |
| `INFO` | `INFO` | Display server statistics (uptime, memory, connected clients) |
| `KEYS` | `KEYS` | List all stored keys |

## Documentation

Expand Down
42 changes: 40 additions & 2 deletions src/commands/client/client_command_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,27 @@ void cmd_persist(const command_args_t args, void (*response_cb)(client_t *client
response_cb(args.client);
}

void cmd_keys(const command_args_t args, void (*response_cb)(client_t *client))
{
if (strncasecmp(args.cmd, "KEYS", 4) != 0) {
return;
}

size_t cmd_len;
unsigned char *keys_cmd = construct_keys_command(&cmd_len);
if (!keys_cmd) {
fprintf(stderr, "Failed to construct KEYS command\n");
return;
}

assert(cmd_len > 0);
assert(args.client->fd > 0);

send(args.client->fd, keys_cmd, cmd_len, 0);
free(keys_cmd);
response_cb(args.client);
}

/*
* TODO: This approach works but is cumbersome to maintain. For future
* reference, lets implement a solution that doesn't require us to have a
Expand All @@ -405,7 +426,8 @@ void cmd_unknown(const command_args_t args,
strncmp(args.cmd, "EXPIRE ", 7) &&
strncmp(args.cmd, "TTL ", 4) &&
strncmp(args.cmd, "PERSIST ", 8) &&
strncmp(args.cmd, "INFO", 5)) {
strncmp(args.cmd, "INFO", 5) &&
strncmp(args.cmd, "KEYS", 4)) {
printf("Unknown command \n");
}
}
Expand All @@ -418,7 +440,8 @@ const cmd_t command_table[] = {
{"cmd_del", cmd_del}, {"cmd_expire", cmd_expire},
{"cmd_ttl", cmd_ttl}, {"cmd_persist", cmd_persist},
{"cmd_unknown", cmd_unknown},
{"cmd_info", cmd_info}};
{"cmd_info", cmd_info},
{"cmd_keys", cmd_keys}};

void execute_command(const char *cmd, client_t *client,
void (*response_cb)(client_t *client))
Expand Down Expand Up @@ -582,6 +605,21 @@ void command_response_handler(client_t *client)
printf("Memory allocation failed\n");
}

} else if (client->buffer[2] == CMD_KEYS) {
const size_t value_len =
client->buffer[3] << 8 | client->buffer[4];
if (value_len == 0) {
printf("(empty list)\n");
} else {
char *data = malloc(value_len + 1);
if (data) {
memcpy(data, &client->buffer[5], value_len);
data[value_len] = '\0';
printf("%s\n", data);
free(data);
}
}

} else if (client->buffer[2] == CMD_PING) {
const size_t value_len =
client->buffer[3] << 8 | client->buffer[4];
Expand Down
2 changes: 2 additions & 0 deletions src/commands/client/client_command_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ void cmd_ttl(command_args_t args, void (*response_cb)(client_t *client));

void cmd_persist(command_args_t args, void (*response_cb)(client_t *client));

void cmd_keys(command_args_t args, void (*response_cb)(client_t *client));

void command_response_handler(client_t *client);

#endif // CLIENT_COMMAND_HANDLERS
1 change: 1 addition & 0 deletions src/commands/common/command_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
#define CMD_EXPIRE 0x0A
#define CMD_TTL 0x0B
#define CMD_PERSIST 0x0C
#define CMD_KEYS 0x0D

#endif // COMMAND_DEFS_H
18 changes: 18 additions & 0 deletions src/commands/common/command_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,21 @@ unsigned char *construct_persist_command(const char *key, size_t *command_len)

return binary_cmd;
}

unsigned char *construct_keys_command(size_t *command_len)
{
const size_t core_cmd_len = 1;
*command_len = 2 + core_cmd_len;

unsigned char *binary_cmd = malloc(*command_len);
if (!binary_cmd) {
return NULL;
}

binary_cmd[0] = core_cmd_len >> 8 & 0xFF;
binary_cmd[1] = core_cmd_len & 0xFF;

binary_cmd[2] = CMD_KEYS;

return binary_cmd;
}
2 changes: 2 additions & 0 deletions src/commands/common/command_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ unsigned char *construct_ttl_command(const char *key, size_t *command_len);

unsigned char *construct_persist_command(const char *key, size_t *command_len);

unsigned char *construct_keys_command(size_t *command_len);

#endif // COMMAND_PARSER_H
20 changes: 20 additions & 0 deletions src/commands/common/command_registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,26 @@ void send_reply(client_t *client, const unsigned char *buffer,
wbuf_append(client, frame, full_frame_length);
}

void send_keys_reply(client_t *client, const unsigned char *data,
size_t data_len)
{
const size_t core_cmd_len = 1 + 2 + data_len;
const size_t full_frame_length = 2 + core_cmd_len;

unsigned char frame[65536];
assert(full_frame_length <= sizeof(frame));

frame[0] = (core_cmd_len >> 8) & 0xFF;
frame[1] = core_cmd_len & 0xFF;
frame[2] = CMD_KEYS;
frame[3] = (data_len >> 8) & 0xFF;
frame[4] = data_len & 0xFF;
memcpy(&frame[5], data, data_len);

assert(client->fd > 0);
wbuf_append(client, frame, full_frame_length);
}

void send_pong(client_t *client, const unsigned char *buffer)
{
const size_t value_len = buffer[3] << 8 | buffer[4];
Expand Down
2 changes: 2 additions & 0 deletions src/commands/common/command_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ void send_ok(client_t *client);
void send_error(client_t *client);
void send_reply(client_t *client, const unsigned char *buffer, size_t bytes_read);
void send_pong(client_t *client, const unsigned char *buffer);
void send_keys_reply(client_t *client, const unsigned char *data,
size_t data_len);

#endif // COMMAND_REGISTRY_H
81 changes: 81 additions & 0 deletions src/commands/server/server_command_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void init_command_handlers(db_t *db)
register_command(CMD_EXPIRE, handle_expire_command);
register_command(CMD_TTL, handle_ttl_command);
register_command(CMD_PERSIST, handle_persist_command);
register_command(CMD_KEYS, handle_keys_command);
}

void handle_set_command(client_t *client, unsigned char *buffer, size_t bytes_read)
Expand Down Expand Up @@ -764,3 +765,83 @@ void handle_persist_command(client_t *client, unsigned char *buffer,

send_ok(client);
}

void handle_keys_command(client_t *client, unsigned char *buffer,
size_t bytes_read)
{
assert(buffer[2] == CMD_KEYS);

const size_t max_output = 65500;
size_t capacity = 4096;
if (capacity > max_output) {
capacity = max_output;
}

char *buf = malloc(capacity);
if (!buf) {
send_error(client);
return;
}

size_t used = 0;
size_t count = 0;
bool truncated = false;

for (size_t i = 0; i < table->size && !truncated; i++) {
hash_table_entry_t *entry = table->buckets[i];
while (entry) {
hash_table_entry_t *next = entry->next;

if (check_and_expire(entry->key, entry->key_len)) {
entry = next;
continue;
}

// Format: "N) key\n"
char num_buf[24];
int num_len = snprintf(num_buf, sizeof(num_buf), "%zu) ", count + 1);

size_t line_len = (size_t)num_len + entry->key_len + 1; // +1 for \n

if (used + line_len > max_output) {
truncated = true;
break;
}

if (used + line_len > capacity) {
size_t new_cap = capacity * 2;
if (new_cap > max_output) {
new_cap = max_output;
}
if (new_cap < used + line_len) {
new_cap = used + line_len;
}
char *tmp = realloc(buf, new_cap);
if (!tmp) {
truncated = true;
break;
}
buf = tmp;
capacity = new_cap;
}

memcpy(buf + used, num_buf, num_len);
used += num_len;
memcpy(buf + used, entry->key, entry->key_len);
used += entry->key_len;
buf[used] = '\n';
used++;

count++;
entry = next;
}
}

if (count == 0) {
send_keys_reply(client, (const unsigned char *)"", 0);
} else {
send_keys_reply(client, (const unsigned char *)buf, used);
}

free(buf);
}
3 changes: 3 additions & 0 deletions src/commands/server/server_command_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ void handle_ttl_command(client_t *client, unsigned char *buffer,
void handle_persist_command(client_t *client, unsigned char *buffer,
size_t bytes_read);

void handle_keys_command(client_t *client, unsigned char *buffer,
size_t bytes_read);

#endif // SERVER_COMMAND_HANDLERS_H
Loading