Skip to content

Commit

Permalink
feat(logging): add DIRECT I/O to file
Browse files Browse the repository at this point in the history
perf(logging): reduce system calls for file
feat(utils): add generate_date_string and number_pad methods
feat(utils): add open_file method
feat(server): add error checking when initializing logs
feat(commands): better getting connected at data for CLIENT INFO command
  • Loading branch information
aloima committed Nov 14, 2024
1 parent a8941ff commit 25f9e71
Show file tree
Hide file tree
Showing 11 changed files with 241 additions and 91 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
CC := gcc
LIBRARIES := -lm -lpthread $(shell pkg-config --cflags --libs openssl) -lcrypt
CFLAGS := -O3 -Wall -Wextra \
-D_GNU_SOURCE \
-D_GNU_SOURCE -D_LARGEFILE64_SOURCE \
-DGIT_HASH=\"$(shell git rev-parse HEAD)\" -DVERSION=\"$(shell git describe --abbrev=0 --tags)\"

compile:
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ A key-value database project for educational purposes.
> Look at:
> [docs/SPECS.md](./docs/SPECS.md) for more technical information,
> [docs/FILE.md](./docs/FILE.md) for information about provided files by tellydb,
> [docs/COMMANDS.md](./docs/COMMANDS.md) for information about commands
> [docs/COMMANDS.md](./docs/COMMANDS.md) for information about commands,
> [docs/AUTH.md](./docs/AUTH.md) for information about authorization
## Quick Start
* Install a client that allows to connect tellydb or redis server
Expand Down
1 change: 0 additions & 1 deletion headers/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ struct Configuration {
uint16_t port;
uint16_t max_clients;
uint8_t allowed_log_levels;
uint32_t max_log_len;
int32_t max_log_lines;
char data_file[49];
char log_file[49];
Expand Down
9 changes: 7 additions & 2 deletions headers/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.h> // IWYU pragma: keep
#include <stdint.h>
#include <stdbool.h>
#include <time.h>

#define streq(s1, s2) (strcmp((s1), (s2)) == 0)

Expand All @@ -30,14 +31,18 @@ enum LogLevel {
LOG_ERR = 0b100,
};

void initialize_logs(struct Configuration *config);
bool initialize_logs(struct Configuration *config);
void write_log(enum LogLevel level, const char *fmt, ...);
void close_logs();
void save_and_close_logs();

bool is_integer(const char *value);
uint32_t get_digit_count(int64_t number);
void number_pad(char *res, const uint32_t value);

void read_string_from_file(const int fd, string_t *string, const bool unallocated, const bool terminator);
void generate_random_string(char *dest, size_t length);
void generate_date_string(char *text, const time_t value);

int open_file(const char *file, int flags);

uint64_t hash(char *key);
8 changes: 6 additions & 2 deletions src/commands/generic/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,20 @@ static void run(struct Client *client, commanddata_t *command, __attribute__((un
}

char buf[512];

char connected_at[21];
generate_date_string(connected_at, client->connected_at);

const size_t buf_len = sprintf(buf, (
"ID: %d\r\n"
"Socket file descriptor: %d\r\n"
"Connected at: %.24s\r\n"
"Connected at: %.20s\r\n"
"Last used command: %s\r\n"
"Library name: %s\r\n"
"Library version: %s\r\n"
"Protocol: %s\r\n"
"Permissions: %s\r\n"
), client->id, client->connfd, ctime(&client->connected_at), client->command->name, lib_name, lib_ver, protocol, permissions);
), client->id, client->connfd, connected_at, client->command->name, lib_name, lib_ver, protocol, permissions);

char res[1024];
const size_t nbytes = sprintf(res, "$%ld\r\n%s\r\n", buf_len, buf);
Expand Down
18 changes: 12 additions & 6 deletions src/server/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ static void close_server() {
write_log(LOG_INFO, "Free'd all memory blocks and closed the server.");

write_log(LOG_INFO, "Closing log file, free'ing configuration and exiting the process...");
close_logs();
save_and_close_logs();
free_configuration(conf);

unlink(".tellylock");
Expand All @@ -110,16 +110,22 @@ static void sigint_signal(__attribute__((unused)) int arg) {
}

void start_server(struct Configuration *config) {
conf = config;
struct stat lock;

if (stat(".tellylock", &lock) != -1) {
fputs("tellydb is already opened in this directory.\n", stderr);
write_log(LOG_ERR, "tellydb is already opened in this directory.");
free_configuration(config);
exit(EXIT_FAILURE);
} else creat(".tellylock", 0);

conf = config;
initialize_logs(conf);
write_log(LOG_INFO, "Initialized logs and configuration.");
if (!initialize_logs(conf)) {
write_log(LOG_ERR, "Cannot initialized logs.");
write_log(LOG_INFO, "Initialized configuration.");
} else {
write_log(LOG_INFO, "Initialized logs and configuration.");
}

write_log(LOG_INFO, "version=" VERSION ", commit hash=" GIT_HASH);

if (conf->default_conf) {
Expand Down Expand Up @@ -242,7 +248,7 @@ void start_server(struct Configuration *config) {
write_log(LOG_INFO, "Read authorization part of database file. Loaded password count: %d", get_password_count());

get_all_keys(authorization_end_at);
write_log(LOG_INFO, "Read all database file to created keyspace. Loaded key count: %d", cache->size);
write_log(LOG_INFO, "Read all database file to create keyspace. Loaded key count: %d", cache->size);
} else {
write_log(LOG_INFO, "Database file is empty. Loaded key and password count: 0");
}
Expand Down
12 changes: 3 additions & 9 deletions src/utils/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ static struct Configuration default_conf = {
.port = 6379,
.max_clients = 128,
.allowed_log_levels = LOG_INFO | LOG_ERR | LOG_WARN,
.max_log_len = 8192,
.max_log_lines = 128,
.data_file = ".tellydb",
.log_file = ".tellylog",
Expand Down Expand Up @@ -81,10 +80,6 @@ struct Configuration parse_configuration(FILE *file) {
break;
}
}
} else if (streq(buf, "MAX_LOG_LEN")) {
buf[0] = '\0';
parse_value(file, buf);
conf.max_log_len = atoi(buf);
} else if (streq(buf, "MAX_LOG_LINES")) {
buf[0] = '\0';
parse_value(file, buf);
Expand Down Expand Up @@ -160,21 +155,20 @@ size_t get_configuration_string(char *buf, struct Configuration conf) {
"# e = error\n\n"
"# Order of keys does not matter\n"
"ALLOWED_LOG_LEVELS=%s\n\n"
"# Specifies maximum writeable log length to STDOUT\n"
"MAX_LOG_LEN=%u\n\n"
"# Specifies maximum line count of logs will be saved to log file, to make undetermined, change it to -1\n"
"# MAX_LOG_LINES * (FILE BLOCK SIZE [512, 4096 or a power of 2] + 1) bytes will be allocated, so be careful\n"
"MAX_LOG_LINES=%d\n\n"
"# Specifies database file where data will be saved\n"
"DATA_FILE=%s\n\n"
"# Specifies log file where logs will be appended\n"
"# Specifies log file where logs will be saved\n"
"LOG_FILE=%s\n\n"
"# Enables/disables creating TLS server\n"
"# If it is enabled, CERT specifies certificate file path of TLS server and PRIVATE_KEY specifies private key file path of TLS server\n"
"# TLS value must be true or false\n"
"TLS=%s\n"
"CERT=%s\n"
"PRIVATE_KEY=%s\n"
), conf.port, conf.max_clients, allowed_log_levels, conf.max_log_len, conf.max_log_lines, conf.data_file, conf.log_file,
), conf.port, conf.max_clients, allowed_log_levels, conf.max_log_lines, conf.data_file, conf.log_file,
conf.tls ? "true" : "false", conf.cert, conf.private_key
);
}
Expand Down
37 changes: 37 additions & 0 deletions src/utils/file.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include "../../headers/utils.h"

#include <errno.h>

#include <fcntl.h>
#include <unistd.h>

int open_file(const char *file, int flags) {
int fd;

if ((fd = open(file, (O_RDWR | O_CREAT | O_DIRECT | flags), (S_IRUSR | S_IWUSR))) == -1) {
switch (errno) {
case EINVAL:
write_log(LOG_ERR, "Direct I/O does not be supported by your file system, cannot open file.");
break;

case EISDIR:
write_log(LOG_ERR, "Specified file is a directory, cannot open file.");
break;

case ENOMEM:
write_log(LOG_ERR, "No available memory to create/open file.");
break;

case EROFS:
write_log(LOG_ERR, "Your file system is read-only, cannot open file for writing.");
break;

default:
write_log(LOG_ERR, "File cannot be opened or created.");
}

return -1;
}

return fd;
}
9 changes: 9 additions & 0 deletions src/utils/integer.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "../../headers/utils.h"

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <stdint.h>
Expand Down Expand Up @@ -30,3 +31,11 @@ uint32_t get_digit_count(int64_t number) {
return 1 + log10(number);
}
}

void number_pad(char *res, const uint32_t value) {
if (value < 10) {
sprintf(res, "0%u", value);
} else if (value < 100) {
sprintf(res, "%u", value);
}
}
Loading

0 comments on commit 25f9e71

Please sign in to comment.