Skip to content

Commit

Permalink
config: postgres: add multiple database functionality
Browse files Browse the repository at this point in the history
This commit contains the necessary changes to implement
a multiple same-database system, utilizing a linked-list.
Each linked list represents a database system, with each
node being a different database.

Changelog:
	- For each section parsed in the config file, create
	  a node. If the config contains multiple of the same
	  section, i.e. multiple databases of the same type,
	  then allocate memory for a new node that will hold
	  the config for each database.
	- Change `db_t` struct to take a `void *` argument
	  instead of a specific database structure, and also
	  change some functions in a similar way. This change
	  was necessary in order to leverage generic programming
	  for the main functions (connect, replicate, close).
	- Added some helper function for the linked list.
	- Added more thread safe functionality to critical sections
	  of the codebase.

Signed-off-by: Panagiotis Foliadis <pfoliadis@hotmail.com>
  • Loading branch information
panosfol committed Jun 7, 2024
1 parent cc07f9e commit 61eba12
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 91 deletions.
8 changes: 5 additions & 3 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ typedef enum backup_type {
FULL,
} backup_type;

typedef struct postgres_t {
typedef struct postgres_node_t {
bool enabled;

d_str_t host;
Expand All @@ -25,7 +25,9 @@ typedef struct postgres_t {

backup_type backup_type;
bool email;
} postgres_t;

struct postgres_node_t *next;
} postgres_node_t;

typedef enum auth_mode_t {
SSL = 1,
Expand Down Expand Up @@ -53,7 +55,7 @@ typedef struct general_t {
} general_t;

typedef struct config_t {
postgres_t *postgres_config;
postgres_node_t *postgres_config;
smtp_t *smtp_config;
general_t *general_config;
} config_t;
Expand Down
13 changes: 11 additions & 2 deletions include/db/db.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define DB_H

#include <stdio.h>
#include <pthread.h>

#include "config.h"

Expand All @@ -10,6 +11,7 @@ typedef int (*init_db_func)(void);

extern init_db_func init_functions[MAX_AVAILABLE_DBS];
extern int num_init_functions;
extern pthread_mutex_t mutex;

#define ADD_FUNC(init_func) \
void __attribute__((constructor)) init_func##_register(void) \
Expand All @@ -28,13 +30,13 @@ extern int num_init_functions;
/* struct db_t
* Holds the information every database will need.
*
* * postgres_t *pg_conf - inherited from the config
* * postgres_node_t *pg_conf - inherited from the config
* * void *host_conn - host connection, should be
* allocated based on the target (e.g. PGconn *)
* * void *target_conn - target connection (same logic as host_conn)
*/
struct db_t {
postgres_t *pg_conf;
void *db_conf;

void *origin_conn;
void *target_conn;
Expand Down Expand Up @@ -73,6 +75,13 @@ struct db_operations {
int (*replicate)(struct db_t *);
};

/*
* execute_db_operations
*
* Returns:
* 0 Success
* -ENOMEM Error allocating memory
*/
int execute_db_operations(void);

#endif
5 changes: 5 additions & 0 deletions include/db/postgres.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*
* Returns:
* 0 on success
* -1 Maximum number of available databases reached
* -ENOMEM Error allocating memory
*
*/
Expand All @@ -34,4 +35,8 @@ int connect_pg(struct db_t *);
void close_pg(struct db_t *pg_db_t);
int replicate(struct db_t *pg_db_t);

bool is_enabled(void *);
const char *get_origin(void *);
void *get_next(void *);

#endif
15 changes: 15 additions & 0 deletions include/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdio.h>

#include "log.h"
#include "db/db.h"

#ifdef _POSIX_C_SOURCE
#include <limits.h>
Expand Down Expand Up @@ -90,4 +91,18 @@ static inline int cnc_strdup(char **string, char *string_to_dup)
*/
void construct_filepath(char *path, char *filename);

/*
* Append `.sql` to a string, mainly to create dump files for SQL-like databases
*/
void construct_sql_dump_file(char *backup_filename, const char *database_name);

/*
* This function is responsible for iterating through a linked list and for
* each node, allocating the correct db structs and populating the `available_dbs` array.
*/
int construct_db(void *db_config, bool (*is_enabled)(void *),
void *(*get_next)(void *), const char *(*get_origin)(void *),
int (*connect_func)(struct db_t *),
void (*close_func)(struct db_t *),
int (*replicate_func)(struct db_t *), size_t size_of_node);
#endif
61 changes: 44 additions & 17 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

config_t *ini_config;
char *log_filepath;
bool new_node = false;

#define CHECK_SECTION(s) strcmp(section, s) == 0
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
Expand Down Expand Up @@ -47,6 +48,14 @@ int handler(void *user, const char *section, const char *name,
}

if (CHECK_SECTION("postgres")) {
// If true, create a new node, and change the head of our linked list.
if (new_node) {
postgres_node_t *temp_node =
CNC_MALLOC(sizeof(postgres_node_t));
temp_node->next = ini_config->postgres_config;
ini_config->postgres_config = temp_node;
new_node = false;
}
if (MATCH("postgres", "enabled")) {
if (strcmp("true", value) == 0) {
ini_config->postgres_config->enabled = true;
Expand Down Expand Up @@ -108,6 +117,12 @@ int handler(void *user, const char *section, const char *name,
"Accepted `enabled` values are \"true\" or \"false\".\n");
return 0;
}
/*
* Since we reached the end of the `postgres` section, we need to change
* the flag so we can create a new node the next time we enter to
* this section.
*/
new_node = true;
} else {
return 0;
}
Expand Down Expand Up @@ -164,7 +179,8 @@ int initialize_config(const char *config_file)
int ret = 0;

ini_config = CNC_MALLOC(sizeof(config_t));
ini_config->postgres_config = CNC_MALLOC(sizeof(postgres_t));
ini_config->postgres_config = CNC_MALLOC(sizeof(postgres_node_t));
ini_config->postgres_config->next = NULL;
ini_config->smtp_config = CNC_MALLOC(sizeof(smtp_t));
ini_config->general_config = CNC_MALLOC(sizeof(general_t));
ini_config->general_config->log_filepath = NULL;
Expand All @@ -183,28 +199,38 @@ int initialize_config(const char *config_file)
return ret;
}

/*
* A helper function to free each node that we allocated. We iterate through the list
* and free all the fields that we have parsed from the `.ini` file.
*/
void config_free_linked_list(postgres_node_t *head)
{
postgres_node_t *temp;
while (head != NULL) {
temp = head;
head = head->next;
free((void *)temp->host.origin);
free((void *)temp->user.origin);
free((void *)temp->password.origin);
free((void *)temp->port.origin);
free((void *)temp->database.origin);
free((void *)temp->host.target);
free((void *)temp->user.target);
free((void *)temp->password.target);
free((void *)temp->port.target);
free((void *)temp->database.target);
free(temp);
}
}

void free_config(void)
{
free((void *)ini_config->postgres_config->host.origin);
free((void *)ini_config->postgres_config->user.origin);
free((void *)ini_config->postgres_config->password.origin);
free((void *)ini_config->postgres_config->port.origin);
free((void *)ini_config->postgres_config->database.origin);

free((void *)ini_config->postgres_config->host.target);
free((void *)ini_config->postgres_config->user.target);
free((void *)ini_config->postgres_config->password.target);
free((void *)ini_config->postgres_config->port.target);
free((void *)ini_config->postgres_config->database.target);
config_free_linked_list(ini_config->postgres_config);

free((void *)ini_config->smtp_config->username);
free((void *)ini_config->smtp_config->password);
free((void *)ini_config->smtp_config->smtp_port);
free((void *)ini_config->smtp_config->smtp_host);

if (ini_config->general_config->log_filepath != NULL) {
free((void *)ini_config->general_config->log_filepath);
}
free((void *)ini_config->smtp_config->from);

for (int i = 0; i < ini_config->smtp_config->to_len; i++) {
Expand All @@ -214,8 +240,9 @@ void free_config(void)
free(ini_config->smtp_config->cc[i]);
}

free((void *)ini_config->general_config->log_filepath);

free(ini_config->smtp_config);
free(ini_config->postgres_config);
free(ini_config->general_config);
free(ini_config);
free(log_filepath);
Expand Down
35 changes: 22 additions & 13 deletions src/db.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "db/postgres.h"
#include "log.h"

#include <bits/pthreadtypes.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <pthread.h>
Expand All @@ -16,6 +17,7 @@ int num_init_functions = 0;
*/
struct db_operations **available_dbs;
size_t db_ops_counter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *db_operation_thread(void *arg)
{
Expand All @@ -37,26 +39,24 @@ void *db_operation_thread(void *arg)
int execute_db_operations(void)
{
int ret = 0;
pthread_t threads[db_ops_counter];
pthread_t threads[MAX_AVAILABLE_DBS];
init_db_func init_function;

// This is needed to access the localtime in a thread-safe manner
tzset();

available_dbs = (struct db_operations **)calloc(
MAX_AVAILABLE_DBS, sizeof(struct db_operations **));

section_foreach_entry(init_function)
{
if (db_ops_counter < MAX_AVAILABLE_DBS) {
int ret = init_function();
if (ret == -ENOMEM) {
pr_error("Error allocating memory\n");
free(available_dbs);
return ret;
}
db_ops_counter++;
} else {
pr_info("Max available database number was reached.\n"
"Executing replication for %ld database systems.\n",
db_ops_counter);
int ret = init_function();
if (ret == -ENOMEM) {
pr_error("Error allocating memory\n");
free(available_dbs);
pthread_mutex_destroy(&mutex);
return ret;
} else if (ret == -1) {
break;
}
}
Expand All @@ -66,6 +66,9 @@ int execute_db_operations(void)
(void *)available_dbs[i]);
if (ret != 0) {
pr_error("Error creating thread: %s\n", strerror(ret));
pthread_mutex_destroy(&mutex);
free(available_dbs);

return ret;
}
}
Expand All @@ -76,11 +79,17 @@ int execute_db_operations(void)
if (ret != 0) {
pr_error("Error joining thread: %s\n",
strerror(ret));
pthread_mutex_destroy(&mutex);
free(available_dbs[i]);

return ret;
}
free(available_dbs[i]);
}
}

pthread_mutex_destroy(&mutex);

free(available_dbs);
return ret;
}
3 changes: 2 additions & 1 deletion src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ extern char *log_filepath;
void construct_log_filename(char *log_filename, const char *log_name)
{
time_t t = time(NULL);
struct tm tm = *localtime(&t);
struct tm tm;
localtime_r(&t, &tm);

snprintf(log_filename, PATH_MAX,
"%scnc_%s_%02d%02d%02d%02d%02d%02d.log", log_filepath,
Expand Down
Loading

0 comments on commit 61eba12

Please sign in to comment.