summaryrefslogtreecommitdiffstats
path: root/src/protocol.c
diff options
context:
space:
mode:
authorrsiddharth <s@ricketyspace.net>2020-04-17 21:02:35 -0400
committerrsiddharth <s@ricketyspace.net>2020-04-17 21:02:35 -0400
commitb924fc2f66d46ee10aa3b800a6521d3940919f9f (patch)
tree130a19d8211874e3ba01203af0d2332506106be4 /src/protocol.c
parent1bab8e87d3875f672e7c36d10aea9e05f657c664 (diff)
nserver/ -> ./
Diffstat (limited to 'src/protocol.c')
-rw-r--r--src/protocol.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644
index 0000000..77b806a
--- /dev/null
+++ b/src/protocol.c
@@ -0,0 +1,310 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright © 2020 rsiddharth <s@ricketyspace.net>
+ */
+
+#include <protocol.h>
+
+static TSTree *tst;
+
+int sscreate(char *key)
+{
+ check(key != NULL || strlen(key) < 1, "key invalid");
+
+ // 1. Check if key is already in the tree.
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+
+ // If it's already there; there's nothing to do.
+ if (rec != NULL && rec->deleted == 0) {
+ return 1;
+ }
+ // If it's already there and deleted, undelete it.
+ if (rec != NULL && rec->deleted == 1) {
+ rec->deleted = 0;
+
+ // Allocate fresh Stats.
+ rec->st = Stats_create();
+ check(rec->st != NULL, "stats creation failed");
+
+ return 2;
+ }
+
+ // 2. Create bstring from 'key'.
+ bstring k = bfromcstr(key);
+ check(k != NULL, "key creation failed");
+
+ // 3. Allocate fresh Stats.
+ Stats *st = Stats_create();
+ check(st != NULL, "stats creation failed");
+
+ // 4. Create Record.
+ rec = (Record *) calloc(1, sizeof(Record));
+ check_mem(rec);
+
+ // 5. Initialize Record.
+ rec->key = k;
+ rec->st = st;
+ rec->deleted = 0;
+
+ // 6. Add Record to tree.
+ tst = TSTree_insert(tst, key, strlen(key), rec);
+ check(tst != NULL, "tstree insert failed");
+
+ return 0;
+ error:
+ return -1;
+}
+
+int ssdelete(char *key)
+{
+ check(key != NULL || strlen(key) < 1, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+ if (rec == NULL) {
+ // key does not exists.
+ return 0;
+ }
+
+ // Mark as deleted.
+ rec->deleted = 1;
+
+ // Free Stats.
+ free(rec->st);
+
+ return 0;
+ error:
+ return -1;
+}
+
+int sssample_parent(char *key, double s)
+{
+ check(key != NULL || strlen(key) < 1, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. Try to get Record with key prefix.
+ Record *rec = (Record *) TSTree_search_prefix(tst, key, strlen(key));
+
+ if (rec == NULL) {
+ // No record with key prefix.
+ return 0;
+ }
+ check(rec->st != NULL, "record's st invalid");
+
+ if (rec->deleted == 1) {
+ // Record was deleted; nop.
+ return 0;
+ }
+
+ // 2. Sample!
+ Stats_sample(rec->st, s);
+
+ return 1;
+ error:
+ return -1;
+}
+
+double sssample(char *key, double s)
+{
+ check(key != NULL || strlen(key) < 1, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. Try to get Record for key.
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+
+ check(rec != NULL, "record not found");
+ check(rec->st != NULL, "record's st invalid");
+ check(rec->deleted != 1, "record was deleted");
+
+ // 2. Sample!
+ Stats_sample(rec->st, s);
+
+ // 3. Sample parent!
+ int rc = sssample_parent(key, s);
+ check(rc >= 0, "sampling parent failed");
+
+ // 4. Get mean.
+ double m = Stats_mean(rec->st);
+
+ return m;
+ error:
+ return -1;
+}
+
+double ssmean(char *key)
+{
+ check(key != NULL || strlen(key) < 1, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. Try to get Record for key.
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+
+ check(rec != NULL, "record not found");
+ check(rec->deleted != 1, "record was deleted");
+ check(rec->st != NULL, "record's st invalid");
+
+ // 2. Get mean.
+ double m = Stats_mean(rec->st);
+
+ return m;
+ error:
+ return -1;
+}
+
+char *ssdump(char *key)
+{
+ check(key != NULL && strlen(key) > 0, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. create bstring from 'key'.
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+
+ check(rec != NULL, "record not found");
+ check(rec->st != NULL, "stats not found for key");
+ check(rec->deleted != 1, "record was deleted");
+
+ // 2. get dump.
+ char *dstr = Stats_dump(rec->st);
+ check(dstr != NULL, "dump failed for key");
+
+ return dstr;
+ error:
+ return NULL;
+}
+
+// meant to be used by sslist.
+void traverse_tree(void *value, void *data)
+{
+ Record *rec = (Record *) value;
+ bstring bstr = (bstring) data;
+
+ check(rec != NULL, "Record is NULL");
+ check(rec->deleted != 1, "Record was deleted");
+ check(bstr != NULL, "bstr is NULL");
+ check(rec->key != NULL, "Record's key is NULL");
+ check(blength(rec->key) > 0, "Record's key is an empty string");
+
+ int rc = bconcat(bstr, rec->key);
+ check(rc == BSTR_OK, "bstr key concat failed");
+
+ rc = bconchar(bstr, '\n');
+ check(rc == BSTR_OK, "bstr newline concat failed");
+
+ error:
+ return;
+}
+
+
+char *sslist()
+{
+ char *list = NULL, *tmp = NULL;
+
+ if (tst == NULL) {
+ list = (char *) calloc(7 + 1, sizeof(char));
+ check_mem(list);
+
+ list = strncpy(list, "EMPTY\n\r", 7);
+
+ return list;
+ }
+
+ // 1. Create "accumulator" string.
+ bstring ks_str = bfromcstr("");
+ check(ks_str != NULL, "error creating keys_str");
+
+ // 2. Accumulate keys into "accumulator" string.
+ TSTree_traverse(tst, traverse_tree, ks_str);
+
+ // 3. Make result.
+ tmp = bstr2cstr(ks_str, ' ');
+
+ list = (char *) calloc(strlen(tmp) + 1, sizeof(char));
+ check_mem(list);
+
+ list = strncpy(list, tmp, strlen(tmp));
+
+ // 4. Clean up.
+ bcstrfree(tmp);
+
+ // 3. Return result.
+ return list;
+ error:
+ if (tmp) {
+ bcstrfree(tmp);
+ }
+ return NULL;
+}
+
+int ssstore(char *key)
+{
+ check(key != NULL && strlen(key) > 0, "key invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. create bstring from 'key'.
+ Record *rec = (Record *) TSTree_search(tst, key, strlen(key));
+
+ check(rec != NULL, "record not found");
+ check(rec->st != NULL, "stats not found for key");
+ check(rec->deleted != 1, "record was deleted");
+
+ // 2. stringify the stats.
+ char *st_str = Stats_stringify(rec->st);
+ check(st_str != NULL, "stats stringify failed");
+
+ // 3. store stats in db.
+ int rc = db_store(key, st_str);
+ check(rc == 0, "db store failed");
+
+ return 0;
+ error:
+ return -1;
+}
+
+int ssload(char *from, char *to)
+{
+ check(from != NULL && strlen(from) > 0, "from invalid");
+ check(to != NULL && strlen(to) > 0, "to invalid");
+ check(tst != NULL, "tstree not initialized");
+
+ // 1. Check if 'to' key already exists.
+ Record *rec = (Record *) TSTree_search(tst, to, strlen(to));
+
+ // 2. if 'to' key exists return immediately with -2.
+ if (rec != NULL && rec->deleted == 0) {
+ return -2;
+ }
+
+ // 3. read 'from' key from database.
+ char *st_str = db_load(from);
+ check(st_str != NULL, "db load failed");
+
+ // 4. construct stats from string.
+ Stats *st = Stats_unstringify(st_str);
+ check(st != NULL, "stats unstringify failed");
+
+ // 5. create Record if needed.
+ int rec_created = 0;
+ if (rec == NULL) {
+ rec = (Record *) calloc(1, sizeof(Record));
+ check_mem(rec);
+ rec_created = 1;
+ }
+
+ // 6. get things ready for insertiion
+ bstring tk = bfromcstr(to);
+ check(tk != NULL, "key creation failed");
+
+ rec->key = tk;
+ rec->st = st;
+ rec->deleted = 0;
+
+ // 7. insert Record into 'to' key in the TSTree if needed.
+ if (rec_created == 1) {
+ tst = TSTree_insert(tst, to, strlen(to), rec);
+ check(tst != NULL, "tstree insert failed");
+ }
+
+ return 0;
+ error:
+ return -1;
+}