Compare commits

...

2 Commits

Author SHA1 Message Date
Jef Roosens 5159b9aead
feat(job-queue): deesigning methods 2023-03-07 11:15:16 +01:00
Jef Roosens f2f69b47f8
chore: format internal header files 2023-02-25 18:54:44 +01:00
8 changed files with 156 additions and 41 deletions

5
.editorconfig 100644
View File

@ -0,0 +1,5 @@
root = true
[*.{c,h}]
indent_style = space
indent_size = 2

View File

@ -12,6 +12,7 @@ LIB := $(BUILD_DIR)/$(LIB_FILENAME)
SRCS != find '$(SRC_DIR)' -iname '*.c' SRCS != find '$(SRC_DIR)' -iname '*.c'
SRCS_H != find $(INC_DIRS) -iname '*.h' SRCS_H != find $(INC_DIRS) -iname '*.h'
SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h'
SRCS_TEST != find '$(TEST_DIR)' -iname '*.c' SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
@ -92,11 +93,11 @@ $(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c
# =====MAINTENANCE===== # =====MAINTENANCE=====
.PHONY: lint .PHONY: lint
lint: lint:
clang-format -n --Werror $(SRCS) $(SRCS_H) clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL)
.PHONY: fmt .PHONY: fmt
fmt: fmt:
clang-format -i $(SRCS) $(SRCS_H) clang-format -i $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL)
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -1,9 +1,9 @@
#ifndef VIETER_JOB_QUEUE #ifndef VIETER_JOB_QUEUE
#define VIETER_JOB_QUEUE #define VIETER_JOB_QUEUE
#include <stdint.h>
#include <stdbool.h>
#include "vieter_cron.h" #include "vieter_cron.h"
#include <stdbool.h>
#include <stdint.h>
/* /*
* The order of these do not imply that they happen in this order. New states * The order of these do not imply that they happen in this order. New states
@ -12,21 +12,84 @@
* other things. * other things.
*/ */
typedef enum vieter_job_state { typedef enum vieter_job_state {
vieter_job_queued = 0, vieter_job_state_queued = 0,
vieter_job_dispatched = 1, vieter_job_state_ready = 1,
vieter_job_finished = 2 vieter_job_state_build_finished = 2,
vieter_job_state_failed = 3
} vieter_job_state; } vieter_job_state;
// This macro should be kept in sync with the above enum // This macro should be kept in sync with the above enum
#define VIETER_JOB_STATES 3 #define VIETER_JOB_STATES 4
/*
* Struct storing a report for why a certain job failed to be processed in the
* given state.
*/
typedef struct vieter_job_failure_report {
vieter_job_state failed_state;
char *msg;
} vieter_job_failure_report;
vieter_job_failure_report *vieter_job_failure_report_init();
void vieter_job_failure_report_free(vieter_job_failure_report **ptp);
/*
* Represents a job currently being processed in the system. A job migrates
* between different states before finally being removed from the queue.
*/
typedef struct vieter_job { typedef struct vieter_job {
int id; uint64_t id;
uint64_t next_scheduled_time; uint64_t next_scheduled_time;
vieter_cron_expression *ce; vieter_cron_expression *schedule;
bool single; void *build_config;
vieter_job_state state; vieter_job_failure_report *failure_report;
uint64_t state_transition_times[VIETER_JOB_STATES]; uint64_t state_transition_times[VIETER_JOB_STATES];
vieter_job_state current_state;
bool single;
bool dispatched;
} vieter_job; } vieter_job;
/*
* Allocate a new vieter_job object.
*/
vieter_job *vieter_job_init();
void vieter_job_free(vieter_job **ptp);
/*
* Represents the actual queue managing the list of jobs.
*/
typedef struct vieter_job_queue vieter_job_queue;
typedef enum vieter_job_queue_error {
vieter_job_queue_ok = 0,
vieter_job_queue_not_found = 1
} vieter_job_queue_error;
/*
* Allocate and initialize a new job queue.
*/
vieter_job_queue *vieter_job_queue_init();
void vieter_job_queue_free(vieter_job_queue **ptp);
/*
* Insert the given job into the system.
*/
vieter_job_queue_error vieter_job_queue_insert(vieter_job *job);
/*
* Dispatch the job with the given id, returning the pointer to the job.
* Dispatching a job removes it from its respective state's queue.
*/
vieter_job_queue_error vieter_job_queue_dispatch(vieter_job **out, uint64_t id);
/*
* Transition the job with the given id to the new state. This sets the
* job's dispatch flag to false, and adds it to the new state's queue.
*/
vieter_job_queue_error vieter_job_queue_transition(uint64_t id,
vieter_job_state new_state);
#endif #endif

View File

@ -5,16 +5,16 @@
#include <stdlib.h> #include <stdlib.h>
typedef struct vieter_heap_node { typedef struct vieter_heap_node {
uint64_t key; uint64_t key;
void *data; void *data;
struct vieter_heap_node *largest_order; struct vieter_heap_node *largest_order;
union { union {
// Roots point to next tree in the heap, other nodes point to their first // Roots point to next tree in the heap, other nodes point to their first
// neighbour. // neighbour.
struct vieter_heap_node *next_tree; struct vieter_heap_node *next_tree;
struct vieter_heap_node *next_largest_order; struct vieter_heap_node *next_largest_order;
} ptr; } ptr;
uint8_t order; uint8_t order;
} vieter_heap_node; } vieter_heap_node;
/* /*
@ -36,7 +36,8 @@ void vieter_heap_tree_free(vieter_heap_node *root);
* Given the roots of the smallest trees in two heaps, merge them into a single * Given the roots of the smallest trees in two heaps, merge them into a single
* large heap. * large heap.
*/ */
vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a, vieter_heap_node *root_b); vieter_heap_node *vieter_heap_tree_merge(vieter_heap_node *root_a,
vieter_heap_node *root_b);
/* /*
* Given the roots of two trees of the same order, merge them into a heap of one * Given the roots of two trees of the same order, merge them into a heap of one

View File

@ -0,0 +1,27 @@
The goal of this job queue design is to process jobs in order, with each job
moving through a pipeline of tasks that need to be completed.
At any given time, a job is in one of a few given states, e.g. "queued". These
states are explained below. Along with this, each job also has a "dispatched"
flag. If this flag is set to true, it means this job is currently being
processed. "Being processed" could mean anything; it depends entirely on the
state a job's in. While a job is dispatched, it is no longer present in the
priority queue of its respective state.
## Job
A job describes a scheduled build as it moves through the pipeline of states.
The job queue datastructure keeps track of all jobs in a central red-black
binary tree. For each state, a priority queue tracks in what order jobs should
be processed.
## States
* `queued`: a job that's in the job queue but does not yet need to be executed
(as defined by its timestamp)
* `ready`: a job that's scheduled for building, with all preprocessing tasks
fulfilled.
* `build_finished`: a job whose build has finished, and is waiting for any
post-build tasks.
* `failed`: a job whose processing failed at some point. Jobs in this state
include a failure report that describes in what state they failed, and why.

View File

@ -0,0 +1,10 @@
#ifndef VIETER_JOB_QUEUE_INTERNAL
#define VIETER_JOB_QUEUE_INTERNAL
#include "vieter_tree.h"
struct vieter_job_queue {
vieter_tree *tree;
};
#endif

View File

@ -16,7 +16,7 @@ struct vieter_tree {
bool vieter_tree_validate(vieter_tree *tree); bool vieter_tree_validate(vieter_tree *tree);
struct vieter_tree_iterator { struct vieter_tree_iterator {
vieter_tree_node *current_node; vieter_tree_node *current_node;
bool started; bool started;
bool done; bool done;
}; };

View File

@ -2,8 +2,8 @@
#define VIETER_TREE_NODE #define VIETER_TREE_NODE
#include "vieter_tree.h" #include "vieter_tree.h"
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
typedef enum vieter_tree_node_flag { typedef enum vieter_tree_node_flag {
vieter_tree_node_black = ((uint8_t)1) << 0, vieter_tree_node_black = ((uint8_t)1) << 0,
@ -13,11 +13,11 @@ typedef enum vieter_tree_node_flag {
} vieter_tree_node_flag; } vieter_tree_node_flag;
typedef struct vieter_tree_node { typedef struct vieter_tree_node {
uint64_t key; uint64_t key;
void *data; void *data;
struct vieter_tree_node *parent; struct vieter_tree_node *parent;
struct vieter_tree_node *children[2]; struct vieter_tree_node *children[2];
uint8_t flags; uint8_t flags;
} vieter_tree_node; } vieter_tree_node;
/* /*
@ -33,27 +33,33 @@ void vieter_tree_node_free(vieter_tree_node *node);
/* /*
* Insert a new key into the given tree. * Insert a new key into the given tree.
*/ */
vieter_tree_error vieter_tree_node_insert(vieter_tree_node *root, uint64_t key, void *data); vieter_tree_error vieter_tree_node_insert(vieter_tree_node *root, uint64_t key,
void *data);
/* /*
* Return the node representing the requested value. * Return the node representing the requested value.
*/ */
vieter_tree_error vieter_tree_node_search_node(vieter_tree_node **out, vieter_tree_node *root, uint64_t key); vieter_tree_error vieter_tree_node_search_node(vieter_tree_node **out,
vieter_tree_node *root,
uint64_t key);
/* /*
* Search for the data represented by the given key. * Search for the data represented by the given key.
*/ */
vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *root, uint64_t key); vieter_tree_error vieter_tree_node_search(void **out, vieter_tree_node *root,
uint64_t key);
/* /*
* Remove the data associated with the given key. * Remove the data associated with the given key.
*/ */
vieter_tree_error vieter_tree_node_remove(void **out, vieter_tree_node **root_ptr, uint64_t key); vieter_tree_error
vieter_tree_node_remove(void **out, vieter_tree_node **root_ptr, uint64_t key);
/* /*
* Set a node's bit flag to the given value. * Set a node's bit flag to the given value.
*/ */
void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag, bool value); void vieter_tree_node_set(vieter_tree_node *node, vieter_tree_node_flag flag,
bool value);
/* /*
* Get whether a node's bit flag is set. * Get whether a node's bit flag is set.
@ -70,12 +76,14 @@ void vieter_tree_node_add_child(vieter_tree_node *parent, uint64_t key,
/* /*
* Replace a node's children array. * Replace a node's children array.
*/ */
void vieter_tree_node_set_children(vieter_tree_node *parent, vieter_tree_node **children); void vieter_tree_node_set_children(vieter_tree_node *parent,
vieter_tree_node **children);
/* /*
* Set a node's left or right child to the given node. * Set a node's left or right child to the given node.
*/ */
void vieter_tree_node_set_child(vieter_tree_node *parent, vieter_tree_node *child, bool right); void vieter_tree_node_set_child(vieter_tree_node *parent,
vieter_tree_node *child, bool right);
/* /*
* Return the in-order successor of the given node, or NULL if it's the last * Return the in-order successor of the given node, or NULL if it's the last