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.
	- Changed `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.
	- Changed the structure of the `configs` file, added `.ini`
	  files for testing single/multple databases

Signed-off-by: Panagiotis Foliadis <pfoliadis@hotmail.com>
Co-developed-by: Charalampos Mitrodimas <charmitro@posteo.net>
  • Loading branch information
panosfol committed Jul 5, 2024
1 parent cc07f9e commit 6b56d40
Show file tree
Hide file tree
Showing 17 changed files with 366 additions and 110 deletions.
32 changes: 32 additions & 0 deletions configs/example.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[general]
log_filepath=

[postgres]
enabled=

origin_host=
origin_user=
origin_password=
origin_port=
origin_database=

target_host=
target_user=
target_password=
target_port=
target_database=

backup_type=
email=

[smtp]
username=
password=
smtp_host=
smtp_port=
auth_mode=
enabled=

from=
to=
cc=
File renamed without changes.
47 changes: 47 additions & 0 deletions configs/tests/multiple_db_config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[postgres]
enabled=true

origin_host=localhost
origin_user=postgres
origin_password=password
origin_port=5432
origin_database=postgres_origin

target_host=localhost
target_user=postgres
target_password=password
target_port=5432
target_database=postgres_origin

backup_type=full
email=false

[postgres]
enabled=true

origin_host=localhost
origin_user=postgres
origin_password=password
origin_port=5433
origin_database=postgres_origin

target_host=localhost
target_user=postgres
target_password=password
target_port=5433
target_database=postgres_origin

backup_type=full
email=false

[smtp]
username = test@posteo.net
password = 123
smtp_host = posteo.de
smtp_port = 587
auth_mode = tls
enabled=true

from = charmitro@posteo.net
to = charmitro@pm.me, trsbisb@gmail.com
cc = charmitro@gmail.com, charmitro@terrasync.net
6 changes: 3 additions & 3 deletions configs/test.ini → configs/tests/single_db_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ origin_host=localhost
origin_user=postgres
origin_password=password
origin_port=5432
origin_database=postgres
origin_database=postgres_origin

target_host=localhost
target_user=postgres
target_password=password
target_port=5432
target_database=postgres
target_database=postgres_origin

backup_type=full
email=true
email=false

[smtp]
username = test@posteo.net
Expand Down
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
14 changes: 12 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,14 @@ struct db_operations {
int (*replicate)(struct db_t *);
};

/*
* execute_db_operations
*
* Returns:
* 0 Success
* -2 Error creating thread
* -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
18 changes: 13 additions & 5 deletions scripts/postgres-down.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
#! /bin/bash

if docker ps --format "{{.Names}}" | grep -q "cnc-postgres"; then
docker stop cnc-postgres
docker rm cnc-postgres
echo "PostgreSQL Docker container was successfully removed."
if docker ps --format "{{.Names}}" | grep -q "cnc-postgres-origin"; then
docker stop cnc-postgres-origin
docker rm cnc-postgres-origin
echo "Postgres-origin docker container was successfully removed."
else
echo "PostgreSQL Docker container is not currently running."
echo "Postgre-origin docker container is not currently running."
fi

if docker ps --format "{{.Names}}" | grep -q "cnc-postgres-target"; then
docker stop cnc-postgres-target
docker rm cnc-postgres-target
echo "Postgres-target docker container was successfully removed."
else
echo "Postgres-target docker container is not currently running."
fi
25 changes: 19 additions & 6 deletions scripts/postgres-up.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,26 @@ To install docker visit (https://docs.docker.com/engine/install/)."
exit 1
fi

docker_args="--name cnc-postgres -d \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 postgres:15"
docker_args_origin="--name cnc-postgres-origin -d \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=postgres_origin \
-p 5432:5432 postgres:14"

if docker run $docker_args; then
echo "Postgres container was successfully set up."
if docker run $docker_args_origin; then
echo "Postgres-origin container was successfully set up."
else
echo "Failed to start the Postgres container."
echo "Failed to start the Postgres-origin container."
exit 1
fi

docker_args_target="--name cnc-postgres-target -d \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=postgres_target \
-p 5433:5432 postgres:14"

if docker run $docker_args_target; then
echo "Postgres-target container was successfully set up."
else
echo "Failed to start the Postgres-target container."
exit 1
fi
3 changes: 3 additions & 0 deletions src/cnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ int process_args(int argc, char **argv)
int c;
char *config_file = NULL;

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

optind = 0;
while ((c = getopt_long(argc, argv, "f:vhV", options, NULL)) != -1) {
switch (c) {
Expand Down
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
Loading

0 comments on commit 6b56d40

Please sign in to comment.