summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/engine/delkeys.c111
-rw-r--r--src/include/engine/engine.h43
-rw-r--r--src/include/engine/file.c98
-rw-r--r--src/include/engine/getkeys.c106
-rw-r--r--src/include/engine/setkeys.c148
-rw-r--r--src/include/engine/utils.c71
-rw-r--r--src/include/engine/utils.h16
-rw-r--r--src/include/mdb.h6
8 files changed, 599 insertions, 0 deletions
diff --git a/src/include/engine/delkeys.c b/src/include/engine/delkeys.c
new file mode 100644
index 0000000..ad9c228
--- /dev/null
+++ b/src/include/engine/delkeys.c
@@ -0,0 +1,111 @@
+#include <threads.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "engine.h"
+#include "utils.h"
+
+static int delkey_helper(void *thr_data);
+static int delkey(tablist_t *, int, char *);
+static struct params *pass(mtx_t *mtx, tablist_t *list, char **keys, int len, int id);
+
+struct params {
+ mtx_t *mtx;
+ tablist_t *copy;
+ char **keys;
+ int len;
+ int id;
+};
+
+
+int delkeys(tablist_t *list, int id, char **keys, int len)
+{
+ mtx_t mtx;
+ if (id >= list[0].len || id < -1 || len < 0)
+ return -1;
+ if (mtx_init(&mtx, mtx_plain) != thrd_success)
+ return -2;
+ int rc = 0;
+ tablist_t *copy = calloc(list[0].len, sizeof(tablist_t));
+ copytab(copy, list);
+
+ if (id == -1) {
+ thrd_t *thrds = calloc(list[0].len, sizeof(thrd_t));
+ for (int i = 0; i < copy[0].len; ++i)
+ thrd_create(&thrds[i], delkey_helper, pass(&mtx, copy, keys, len, i));
+ for (int i = 0; i < copy[0].len; ++i) {
+ if (rc)
+ thrd_join(thrds[i], NULL);
+ else
+ thrd_join(thrds[i], &rc);
+ }
+ free(thrds);
+ } else
+ rc = delkey_helper(pass(&mtx, copy, keys, len, id));
+
+ if (!rc) {
+ dellist(list);
+ memmove(list, copy, copy[0].len * sizeof(tablist_t));
+ } else
+ dellist(copy);
+ mtx_destroy(&mtx);
+ free(copy);
+ return rc;
+}
+
+static int delkey_helper(void *thr_data)
+{
+ int rc = 0;
+ struct params *p = (struct params *) thr_data;
+
+ mtx_lock(p->mtx);
+ if (p->len > 0 && p->keys != NULL)
+ for (int i = 0; i < p->len; ++i) {
+ if (p->keys[i] == NULL) {
+ mtx_unlock(p->mtx);
+ free(p);
+ return -3;
+ }
+ rc = delkey(p->copy, p->id, p->keys[i]);
+ }
+ else {
+ tablist_t *indexes = getkeys(p->copy, p->id, NULL, 0);
+ for (int i = 0; indexes[0].tab[i].flag; ++i)
+ rc = delkey(p->copy, p->id, indexes[0].tab[i].key);
+ free(indexes);
+ }
+ mtx_unlock(p->mtx);
+
+ free(p);
+ return rc;
+}
+
+static int delkey(tablist_t *list, int id, char *key)
+{
+ int idx = hash(key);
+ if (list[id].tab[idx].key == NULL)
+ return 1;
+ while (strcmp(list[id].tab[idx].key, key) && idx < TABLEN)
+ idx++;
+ if (idx >= TABLEN)
+ return 2;
+ free(list[id].tab[idx].key);
+ list[id].tab[idx].key = NULL;
+ if (list[id].tab[idx].flag == 3) {
+ free(list[id].tab[idx].value.str);
+ list[id].tab[idx].value.str = NULL;
+ }
+ list[id].tab[idx].flag = 0;
+ return 0;
+}
+
+static struct params *pass(mtx_t *mtx, tablist_t *list, char **keys, int len, int id)
+{
+ struct params *p = calloc(1, sizeof(struct params));
+ p->mtx = mtx;
+ p->copy = list;
+ p->keys = keys;
+ p->len = len;
+ p->id = id;
+ return p;
+}
diff --git a/src/include/engine/engine.h b/src/include/engine/engine.h
new file mode 100644
index 0000000..d233bdd
--- /dev/null
+++ b/src/include/engine/engine.h
@@ -0,0 +1,43 @@
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#define TABLEN 1024
+
+typedef struct {
+ char *key;
+ int flag;
+ union {
+ char *str;
+ double num;
+ unsigned int boolean : 1;
+ } value;
+} tabidx_t;
+
+typedef struct {
+ int len;
+ tabidx_t tab[TABLEN];
+} tablist_t;
+
+/* getkeys: gets the provided keys from the provided id,
+ * if the id is set to -1, it will get the provided key from every document,
+ * if keys is NULL, it will get every key. */
+tablist_t *getkeys(tablist_t *list, int id, char **keys, int len);
+
+/* setkeys: sets the provided key-value pairs in the provided object,
+ * if the id is -1, it will set the provided pairs in every object. */
+int setkeys(tablist_t **list, int id, char **pairs, int len);
+
+/* delkeys: deletes the provided keys from the provided id,
+ * if the id is -1, it will delete the provided key from every document,
+ * if keys is NULL it, will delete every key. */
+int delkeys(tablist_t *list, int id, char **keys, int len);
+
+/* readdb: reads the provided db file,
+ * if the filename is NULL, it will return an empty table list,
+ * if the file format is invalid, it will return NULL. */
+tablist_t *readdb(char *filename);
+
+/* writedb: writes a table list to a database file. */
+void writedb(char *filename, tablist_t *list);
+
+#endif
diff --git a/src/include/engine/file.c b/src/include/engine/file.c
new file mode 100644
index 0000000..4da8b2d
--- /dev/null
+++ b/src/include/engine/file.c
@@ -0,0 +1,98 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "engine.h"
+
+static char *getpair(int *c, FILE *fp);
+
+// TODO: reimplement this to read file in FI format
+tablist_t *readdb(char *filename)
+{
+ int len = 2;
+ tablist_t *list = calloc(len, sizeof(tablist_t));
+ list[0].len = len;
+ FILE *fp;
+ if (filename == NULL ||
+ (fp = fopen(filename, "rb")) == NULL)
+ return list;
+
+ int c, i = 0, open = 0;
+ char *p;
+ while ((c = fgetc(fp)) != EOF) {
+ switch (c) {
+ case 250:
+ p = getpair(&c, fp);
+ if (p == NULL) goto fail;
+ setkeys(&list, i, &p, 1);
+ free(p);
+ break;
+ case 251:
+ if (open == 1) goto fail;
+ open = 1;
+ break;
+ case 254:
+ open = 0;
+ i++;
+ break;
+ default:
+ goto fail;
+ }
+ }
+ fclose(fp);
+ return list;
+
+fail:
+ fclose(fp);
+ delkeys(list, -1, NULL, 0);
+ free(list);
+ return NULL;
+}
+
+// TODO: rewrite this function to write data in FI format
+void writedb(char *filename, tablist_t *list)
+{
+ FILE *fp = fopen(filename, "wb");
+ if (fp == NULL)
+ return;
+ for (int i = 0; i < list[0].len; ++i) {
+ fputc(0xFB, fp);
+ tablist_t *indexes = getkeys(list, i, NULL, 0);
+ for (int j = 0; indexes[0].tab[j].flag; ++j) {
+ fprintf(fp, "\xfa%s:", indexes[0].tab[j].key);
+ switch (indexes[0].tab[j].flag) {
+ case 1:
+ fprintf(fp, "%.2lf\xfc", indexes[0].tab[j].value.num);
+ break;
+ case 2:
+ fprintf(fp, "%s\xfc", indexes[0].tab[j].value.boolean ?
+ "true" : "false");
+ break;
+ case 3:
+ fprintf(fp, "%s\xfc", indexes[0].tab[j].value.str);
+ break;
+ }
+ }
+ free(indexes);
+ fputc(0xFE, fp);
+ }
+ fclose(fp);
+}
+
+static char *getpair(int *c, FILE *fp)
+{
+ char *pair = calloc(3, sizeof(char));
+ int i = 0, len = 3;
+ while ((*c = fgetc(fp)) != 252 && *c != EOF) {
+ if (i >= len)
+ pair = realloc(pair, ++len * sizeof(char));
+ pair[i++] = *c;
+ }
+ pair = realloc(pair, ++len * sizeof(char));
+ pair[i] = '\0';
+ if (*c != 252) {
+ free(pair);
+ return NULL;
+ }
+ return pair;
+}
diff --git a/src/include/engine/getkeys.c b/src/include/engine/getkeys.c
new file mode 100644
index 0000000..ae2eb73
--- /dev/null
+++ b/src/include/engine/getkeys.c
@@ -0,0 +1,106 @@
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <threads.h>
+
+#include "engine.h"
+#include "utils.h"
+
+static tabidx_t getkey(tablist_t *list, int id, char *key);
+
+static int getkeys_helper(void *data);
+
+struct params {
+ mtx_t *mtx;
+ tablist_t *list;
+ tablist_t *ret;
+ char **keys;
+ int len;
+ int lid;
+ int pid;
+};
+
+static struct params *pass(mtx_t *mtx, tablist_t *list, tablist_t *ret, char **keys, int len, int lid, int pid);
+
+tablist_t *getkeys(tablist_t *list, int id, char **keys, int klen)
+{
+ mtx_t mtx;
+ if (id >= list[0].len || id < -1 || mtx_init(&mtx, mtx_plain) != thrd_success)
+ return NULL;
+ int rc = 0;
+ int len = id == -1 ? list[0].len : 1;
+ tablist_t *indexes = calloc(len, sizeof(tablist_t));
+ indexes[0].len = len;
+ if (id >= 0)
+ rc = getkeys_helper(pass(&mtx, list, indexes, keys, klen, id, 0));
+ else {
+ thrd_t *thrds = calloc(list[0].len, sizeof(thrd_t));
+ for (int i = 0; i < list[0].len; ++i)
+ thrd_create(&thrds[i], getkeys_helper, pass(&mtx, list, indexes, keys, klen, i, i));
+ for (int i = 0; i < list[0].len; ++i) {
+ if (rc)
+ thrd_join(thrds[i], NULL);
+ else
+ thrd_join(thrds[i], &rc);
+ }
+ free(thrds);
+ }
+
+ mtx_destroy(&mtx);
+ if (!rc)
+ return indexes;
+ else {
+ free(indexes);
+ return NULL;
+ }
+}
+
+static int getkeys_helper(void *data)
+{
+ struct params *p = (struct params *) data;
+ int rc = 0;
+
+ mtx_lock(p->mtx);
+ if (p->keys == NULL) {
+ for (int i = 0, j = 0; i < TABLEN; ++i)
+ if (p->list[p->lid].tab[i].flag)
+ p->ret[p->pid].tab[j++] = p->list[p->lid].tab[i];
+ } else {
+ for (int i = 0, j = 0; i < p->len; ++i) {
+ tabidx_t idx = getkey(p->list, p->lid, p->keys[i]);
+ if (idx.flag == 0)
+ rc = 1;
+ else
+ p->ret[p->pid].tab[j++] = idx;
+ }
+ }
+ mtx_unlock(p->mtx);
+ free(p);
+ return rc;
+}
+
+static struct params *pass(mtx_t *mtx, tablist_t *list, tablist_t *ret, char **keys, int len, int lid, int pid)
+{
+ struct params *p = calloc(1, sizeof(struct params));
+ p->mtx = mtx;
+ p->list = list;
+ p->ret = ret;
+ p->keys = keys;
+ p->len = len;
+ p->lid = lid;
+ p->pid = pid;
+ return p;
+}
+
+static tabidx_t getkey(tablist_t *list, int id, char *key)
+{
+ int idx = hash(key);
+ if (list[id].tab[idx].key == NULL)
+ return (tabidx_t) { .key = NULL, .flag = 0, .value = { 0 } };
+
+ while (strcmp(list[id].tab[idx].key, key) && idx < TABLEN)
+ idx++;
+ if (idx >= TABLEN)
+ return (tabidx_t) { .key = NULL, .flag = 0, .value = { 0 } };
+ return list[id].tab[idx];
+}
diff --git a/src/include/engine/setkeys.c b/src/include/engine/setkeys.c
new file mode 100644
index 0000000..34ef3d2
--- /dev/null
+++ b/src/include/engine/setkeys.c
@@ -0,0 +1,148 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <threads.h>
+
+#include "engine.h"
+#include "utils.h"
+
+static int setkey_helper(void *thr_data);
+static int setkey(tablist_t **, int, char *);
+static char **getkv(char *pair);
+
+struct params {
+ mtx_t *mtx;
+ tablist_t **copy;
+ char *pair;
+ int id;
+};
+
+static struct params *pass(mtx_t *mtx, tablist_t **copy, char *pair, int id);
+
+int setkeys(tablist_t **list, int id, char **pairs, int len)
+{
+ mtx_t mtx;
+ if (id < -1 || pairs == NULL || len <= 0)
+ return -1;
+ if (mtx_init(&mtx, mtx_plain) != thrd_success)
+ return -2;
+ int rc = 0;
+ tablist_t *copy = calloc((*list)[0].len, sizeof(tablist_t));
+ copytab(copy, *list);
+
+ for (int i = 0; i < len; ++i) {
+ char *pair = pairs[i];
+ if (id == -1) {
+ thrd_t *thrds = calloc((*list)[0].len, sizeof(thrd_t));
+ for (int i = 0; i < copy[0].len; ++i)
+ thrd_create(&thrds[i], setkey_helper, pass(&mtx, &copy, pair, i));
+ for (int i = 0; i < copy[0].len; ++i) {
+ if (rc)
+ thrd_join(thrds[i], NULL);
+ else
+ thrd_join(thrds[i], &rc);
+ }
+ free(thrds);
+ }
+ else
+ rc = setkey_helper(pass(&mtx, &copy, pair, id));
+ }
+
+ if (!rc) {
+ if (copy[0].len > (*list)[0].len)
+ *list = realloc(*list, copy[0].len * sizeof(tablist_t));
+ dellist(*list);
+ copytab(*list, copy);
+ }
+ mtx_destroy(&mtx);
+ dellist(copy);
+ free(copy);
+ return rc;
+}
+
+static int setkey_helper(void *thr_data)
+{
+ int rc;
+ struct params *p = (struct params *) thr_data;
+
+ mtx_lock(p->mtx);
+ rc = setkey(p->copy, p->id, p->pair);
+ mtx_unlock(p->mtx);
+
+ free(p);
+ return rc;
+}
+
+static int setkey(tablist_t **list, int id, char *pair)
+{
+ if (pair == NULL)
+ return 1;
+ if (id >= (*list)[0].len) {
+ *list = realloc(*list, (id + 1) * sizeof(tablist_t));
+ for (int i = (*list)[0].len; i <= id; ++i) {
+ for (int j = 0; j < TABLEN; ++j)
+ (*list)[i].tab[j] = (tabidx_t) { NULL, 0, { 0 } };
+ }
+ (*list)[0].len = id + 1;
+ }
+ char **kv = getkv(pair);
+ if (kv == NULL)
+ return 2;
+
+ int idx = hash(kv[0]);
+ while ((*list)[id].tab[idx].key != NULL &&
+ strcmp((*list)[id].tab[idx].key, kv[0]) &&
+ idx < TABLEN) idx++;
+ if (idx >= TABLEN)
+ return 2;
+ if (!(*list)[id].tab[idx].key)
+ (*list)[id].tab[idx].key = kv[0];
+ else {
+ free(kv[0]);
+ if ((*list)[id].tab[idx].flag == 3)
+ free((*list)[id].tab[idx].value.str);
+ }
+ char *end;
+ double num = strtod(kv[1], &end);
+ if (*end == '\0') {
+ (*list)[id].tab[idx].flag = 1;
+ (*list)[id].tab[idx].value.num = num;
+ } else if (!strcmp(kv[1], "true") || !strcmp(kv[1], "false")) {
+ (*list)[id].tab[idx].flag = 2;
+ (*list)[id].tab[idx].value.boolean = !strcmp(kv[1], "true");
+ } else {
+ (*list)[id].tab[idx].flag = 3;
+ (*list)[id].tab[idx].value.str = calloc(strlen(kv[1]) + 1, sizeof(char));
+ strcpy((*list)[id].tab[idx].value.str, kv[1]);
+ }
+ free(kv[1]);
+ free(kv);
+ return 0;
+}
+
+static char **getkv(char *pair)
+{
+ char **kv = calloc(2, sizeof(char *));
+ int i = 0;
+ while (pair[i] != ':' && i < strlen(pair))
+ i++;
+ if (i >= strlen(pair)) {
+ free(kv);
+ return NULL;
+ }
+ kv[0] = calloc(i + 1, sizeof(char));
+ strncpy(kv[0], pair, i);
+ kv[1] = calloc(strlen(pair) - i, sizeof(char));
+ strcpy(kv[1], pair + i + 1);
+ return kv;
+}
+
+static struct params *pass(mtx_t *mtx, tablist_t **copy, char *pair, int id)
+{
+ struct params *p = calloc(1, sizeof(struct params));
+ p->mtx = mtx;
+ p->copy = copy;
+ p->pair = pair;
+ p->id = id;
+ return p;
+}
diff --git a/src/include/engine/utils.c b/src/include/engine/utils.c
new file mode 100644
index 0000000..909c123
--- /dev/null
+++ b/src/include/engine/utils.c
@@ -0,0 +1,71 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils.h"
+
+static int delkey(tablist_t *, int, char *);
+
+void dellist(tablist_t *list)
+{
+ for (int i = 0; i < list[0].len; ++i) {
+ tablist_t *indexes = getkeys(list, i, NULL, 0);
+ for (int j = 0; indexes[0].tab[j].flag; ++j)
+ delkey(list, i, indexes[0].tab[j].key);
+ free(indexes);
+ }
+}
+
+int hash(char *key)
+{
+ unsigned long h = 5381;
+ for (int i = 0; i < strlen(key); ++i)
+ h = ((h << 5) + h) + key[i];
+ return h % TABLEN;
+}
+
+tablist_t *copytab(tablist_t *dst, tablist_t *src)
+{
+ if (dst == NULL)
+ return NULL;
+ dst[0].len = src[0].len;
+ for (int i = 0; i < src[0].len; ++i) {
+ for (int j = 0; j < TABLEN; ++j) {
+ dst[i].tab[j] = (tabidx_t) { NULL, 0, { 0 } };
+ if (src[i].tab[j].flag) {
+ switch (src[i].tab[j].flag) {
+ case 3:
+ dst[i].tab[j].value.str =
+ calloc(strlen(src[i].tab[j].value.str) + 1, sizeof(char));
+ strcpy(dst[i].tab[j].value.str, src[i].tab[j].value.str);
+ break;
+ default:
+ dst[i].tab[j].value = src[i].tab[j].value;
+ break;
+ }
+ dst[i].tab[j].flag = src[i].tab[j].flag;
+ dst[i].tab[j].key = calloc(strlen(src[i].tab[j].key) + 1, sizeof(char));
+ strcpy(dst[i].tab[j].key, src[i].tab[j].key);
+ }
+ }
+ }
+ return dst;
+}
+
+static int delkey(tablist_t *list, int id, char *key)
+{
+ int idx = hash(key);
+ if (list[id].tab[idx].key == NULL)
+ return 1;
+ while (strcmp(list[id].tab[idx].key, key) && idx < TABLEN)
+ idx++;
+ if (idx >= TABLEN)
+ return 2;
+ free(list[id].tab[idx].key);
+ list[id].tab[idx].key = NULL;
+ if (list[id].tab[idx].flag == 3) {
+ free(list[id].tab[idx].value.str);
+ list[id].tab[idx].value.str = NULL;
+ }
+ list[id].tab[idx].flag = 0;
+ return 0;
+}
diff --git a/src/include/engine/utils.h b/src/include/engine/utils.h
new file mode 100644
index 0000000..54bfc17
--- /dev/null
+++ b/src/include/engine/utils.h
@@ -0,0 +1,16 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include "engine.h"
+
+// dellist: deletes the provided table
+void dellist(tablist_t *list);
+
+/* hash: calculates the DJB2 hash of a string,
+ * and returns that mod TABLEN */
+int hash(char *str);
+
+// copytab: copys table src into table dst
+tablist_t *copytab(tablist_t *dst, tablist_t *src);
+
+#endif
diff --git a/src/include/mdb.h b/src/include/mdb.h
new file mode 100644
index 0000000..cba4aa8
--- /dev/null
+++ b/src/include/mdb.h
@@ -0,0 +1,6 @@
+#ifndef MDB_H
+#define MDB_H
+
+#include "engine/engine.h"
+
+#endif